From 14f7622ef4404eb22b7396458b6382b96f8af128 Mon Sep 17 00:00:00 2001 From: Vyacheslav Egorov Date: Fri, 9 Feb 2024 14:10:49 +0000 Subject: [PATCH] [vm] Remove bin/*_android{.cc,.h} and use Linux implementations. 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 Commit-Queue: Slava Egorov --- runtime/bin/builtin_impl_sources.gni | 7 - runtime/bin/crypto_android.cc | 44 - runtime/bin/crypto_linux.cc | 4 +- runtime/bin/dartutils.cc | 31 +- runtime/bin/dartutils.h | 4 + runtime/bin/directory_android.cc | 512 -------- runtime/bin/directory_linux.cc | 14 +- runtime/bin/eventhandler.h | 6 +- runtime/bin/eventhandler_android.cc | 443 ------- runtime/bin/eventhandler_android.h | 100 -- runtime/bin/eventhandler_linux.cc | 4 +- runtime/bin/fdutils_android.cc | 142 -- runtime/bin/fdutils_linux.cc | 4 +- runtime/bin/file_android.cc | 793 ----------- runtime/bin/file_linux.cc | 6 +- runtime/bin/file_system_watcher_android.cc | 155 --- runtime/bin/file_system_watcher_linux.cc | 4 +- .../bin/{ifaddrs-android.cc => ifaddrs.cc} | 4 +- runtime/bin/{ifaddrs-android.h => ifaddrs.h} | 17 +- runtime/bin/io_impl_sources.gni | 16 +- runtime/bin/namespace_android.cc | 159 --- runtime/bin/namespace_linux.cc | 4 +- runtime/bin/platform_android.cc | 208 --- runtime/bin/platform_linux.cc | 34 +- runtime/bin/platform_win.cc | 13 +- runtime/bin/process_android.cc | 1169 ----------------- runtime/bin/process_linux.cc | 4 +- runtime/bin/security_context_android.cc | 69 - runtime/bin/security_context_linux.cc | 24 +- runtime/bin/socket_android.cc | 283 ---- runtime/bin/socket_base.h | 6 +- runtime/bin/socket_base_android.cc | 505 ------- runtime/bin/socket_base_android.h | 17 - runtime/bin/socket_base_linux.cc | 4 +- runtime/bin/socket_base_posix.cc | 5 +- runtime/bin/socket_linux.cc | 14 +- runtime/bin/stdio_android.cc | 139 -- runtime/bin/stdio_linux.cc | 4 +- runtime/bin/sync_socket_android.cc | 92 -- runtime/bin/sync_socket_linux.cc | 4 +- runtime/bin/thread.h | 4 +- runtime/bin/thread_android.cc | 277 ---- runtime/bin/thread_android.h | 57 - runtime/bin/thread_linux.cc | 6 +- runtime/bin/utils_android.cc | 114 -- runtime/bin/utils_linux.cc | 4 +- 46 files changed, 139 insertions(+), 5390 deletions(-) delete mode 100644 runtime/bin/crypto_android.cc delete mode 100644 runtime/bin/directory_android.cc delete mode 100644 runtime/bin/eventhandler_android.cc delete mode 100644 runtime/bin/eventhandler_android.h delete mode 100644 runtime/bin/fdutils_android.cc delete mode 100644 runtime/bin/file_android.cc delete mode 100644 runtime/bin/file_system_watcher_android.cc rename runtime/bin/{ifaddrs-android.cc => ifaddrs.cc} (98%) rename runtime/bin/{ifaddrs-android.h => ifaddrs.h} (63%) delete mode 100644 runtime/bin/namespace_android.cc delete mode 100644 runtime/bin/platform_android.cc delete mode 100644 runtime/bin/process_android.cc delete mode 100644 runtime/bin/security_context_android.cc delete mode 100644 runtime/bin/socket_android.cc delete mode 100644 runtime/bin/socket_base_android.cc delete mode 100644 runtime/bin/socket_base_android.h delete mode 100644 runtime/bin/stdio_android.cc delete mode 100644 runtime/bin/sync_socket_android.cc delete mode 100644 runtime/bin/thread_android.cc delete mode 100644 runtime/bin/thread_android.h delete mode 100644 runtime/bin/utils_android.cc diff --git a/runtime/bin/builtin_impl_sources.gni b/runtime/bin/builtin_impl_sources.gni index feb1ee80a3b..0db1b7655bc 100644 --- a/runtime/bin/builtin_impl_sources.gni +++ b/runtime/bin/builtin_impl_sources.gni @@ -9,7 +9,6 @@ builtin_impl_sources = [ "crypto.cc", "crypto.h", - "crypto_android.cc", "crypto_fuchsia.cc", "crypto_linux.cc", "crypto_macos.cc", @@ -18,7 +17,6 @@ builtin_impl_sources = [ "dartutils.h", "directory.cc", "directory.h", - "directory_android.cc", "directory_fuchsia.cc", "directory_linux.cc", "directory_macos.cc", @@ -26,13 +24,11 @@ builtin_impl_sources = [ "exe_utils.cc", "exe_utils.h", "fdutils.h", - "fdutils_android.cc", "fdutils_fuchsia.cc", "fdutils_linux.cc", "fdutils_macos.cc", "file.cc", "file.h", - "file_android.cc", "file_fuchsia.cc", "file_linux.cc", "file_macos.cc", @@ -47,8 +43,6 @@ builtin_impl_sources = [ "thread.h", "thread_absl.cc", "thread_absl.h", - "thread_android.cc", - "thread_android.h", "thread_fuchsia.cc", "thread_fuchsia.h", "thread_linux.cc", @@ -59,7 +53,6 @@ builtin_impl_sources = [ "thread_win.h", "utils.cc", "utils.h", - "utils_android.cc", "utils_fuchsia.cc", "utils_linux.cc", "utils_macos.cc", diff --git a/runtime/bin/crypto_android.cc b/runtime/bin/crypto_android.cc deleted file mode 100644 index f8b1a9f7366..00000000000 --- a/runtime/bin/crypto_android.cc +++ /dev/null @@ -1,44 +0,0 @@ -// 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_ANDROID) - -#include // NOLINT -#include // NOLINT - -#include "bin/crypto.h" -#include "bin/fdutils.h" -#include "platform/signal_blocker.h" - -namespace dart { -namespace bin { - -bool Crypto::GetRandomBytes(intptr_t count, uint8_t* buffer) { - ThreadSignalBlocker signal_blocker(SIGPROF); - intptr_t fd = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER( - open("/dev/urandom", O_RDONLY | O_CLOEXEC)); - if (fd < 0) { - return false; - } - intptr_t bytes_read = 0; - do { - int res = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER( - read(fd, buffer + bytes_read, count - bytes_read)); - if (res < 0) { - int err = errno; - close(fd); - errno = err; - return false; - } - bytes_read += res; - } while (bytes_read < count); - close(fd); - return true; -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/crypto_linux.cc b/runtime/bin/crypto_linux.cc index 957578e08f7..cda1684c5c1 100644 --- a/runtime/bin/crypto_linux.cc +++ b/runtime/bin/crypto_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include // NOLINT #include // NOLINT @@ -41,4 +41,4 @@ bool Crypto::GetRandomBytes(intptr_t count, uint8_t* buffer) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc index 733ecae8613..aea5f13a35b 100644 --- a/runtime/bin/dartutils.cc +++ b/runtime/bin/dartutils.cc @@ -792,19 +792,40 @@ Dart_Handle DartUtils::NewInternalError(const char* message) { } Dart_Handle DartUtils::NewStringFormatted(const char* format, ...) { + va_list args; + va_start(args, format); + char* result = ScopedCStringVFormatted(format, args); + va_end(args); + return NewString(result); +} + +char* DartUtils::ScopedCStringVFormatted(const char* format, va_list args) { va_list measure_args; - va_start(measure_args, format); + va_copy(measure_args, args); intptr_t len = vsnprintf(nullptr, 0, format, measure_args); + if (len < 0) { + return nullptr; + } va_end(measure_args); - char* buffer = reinterpret_cast(Dart_ScopeAllocate(len + 1)); + char* buffer = ScopedCString(len + 1); MSAN_UNPOISON(buffer, (len + 1)); va_list print_args; - va_start(print_args, format); - vsnprintf(buffer, (len + 1), format, print_args); + va_copy(print_args, args); + len = vsnprintf(buffer, (len + 1), format, print_args); + if (len < 0) { + return nullptr; + } va_end(print_args); + return buffer; +} - return NewString(buffer); +char* DartUtils::ScopedCStringFormatted(const char* format, ...) { + va_list args; + va_start(args, format); + char* result = ScopedCStringVFormatted(format, args); + va_end(args); + return result; } bool DartUtils::SetOriginalWorkingDirectory() { diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h index 101707808be..8dde2ba71bd 100644 --- a/runtime/bin/dartutils.h +++ b/runtime/bin/dartutils.h @@ -228,6 +228,10 @@ class DartUtils { return result; } + static char* ScopedCStringFormatted(const char* format, ...) + PRINTF_ATTRIBUTE(1, 2); + static char* ScopedCStringVFormatted(const char* format, va_list args); + // Create a new Dart InternalError object with the provided message. static Dart_Handle NewError(const char* format, ...); static Dart_Handle NewInternalError(const char* message); diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc deleted file mode 100644 index 124850c6e7c..00000000000 --- a/runtime/bin/directory_android.cc +++ /dev/null @@ -1,512 +0,0 @@ -// 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_ANDROID) - -#include "bin/directory.h" - -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#include "bin/crypto.h" -#include "bin/dartutils.h" -#include "bin/fdutils.h" -#include "bin/file.h" -#include "bin/namespace.h" -#include "bin/platform.h" -#include "platform/signal_blocker.h" - -namespace dart { -namespace bin { - -PathBuffer::PathBuffer() : length_(0) { - data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT -} - -PathBuffer::~PathBuffer() { - free(data_); -} - -bool PathBuffer::AddW(const wchar_t* name) { - UNREACHABLE(); - return false; -} - -char* PathBuffer::AsString() const { - return reinterpret_cast(data_); -} - -wchar_t* PathBuffer::AsStringW() const { - UNREACHABLE(); - return nullptr; -} - -const char* PathBuffer::AsScopedString() const { - return DartUtils::ScopedCopyCString(AsString()); -} - -bool PathBuffer::Add(const char* name) { - char* data = AsString(); - int written = snprintf(data + length_, PATH_MAX - length_, "%s", name); - data[PATH_MAX] = '\0'; - if ((written <= PATH_MAX - length_) && (written >= 0) && - (static_cast(written) == strnlen(name, PATH_MAX + 1))) { - length_ += written; - return true; - } else { - errno = ENAMETOOLONG; - return false; - } -} - -void PathBuffer::Reset(intptr_t new_length) { - length_ = new_length; - AsString()[length_] = '\0'; -} - -// A linked list of symbolic links, with their unique file system identifiers. -// These are scanned to detect loops while doing a recursive directory listing. -struct LinkList { - uint64_t dev; - uint64_t ino; - LinkList* next; -}; - -ListType DirectoryListingEntry::Next(DirectoryListing* listing) { - if (done_) { - return kListDone; - } - - if (fd_ == -1) { - ASSERT(lister_ == 0); - NamespaceScope ns(listing->namespc(), listing->path_buffer().AsString()); - const int listingfd = - TEMP_FAILURE_RETRY(openat(ns.fd(), ns.path(), O_DIRECTORY)); - if (listingfd < 0) { - done_ = true; - return kListError; - } - fd_ = listingfd; - } - - if (lister_ == 0) { - do { - lister_ = reinterpret_cast(fdopendir(fd_)); - } while ((lister_ == 0) && (errno == EINTR)); - if (lister_ == 0) { - done_ = true; - return kListError; - } - if (parent_ != nullptr) { - if (!listing->path_buffer().Add(File::PathSeparator())) { - return kListError; - } - } - path_length_ = listing->path_buffer().length(); - } - // Reset. - listing->path_buffer().Reset(path_length_); - ResetLink(); - - // Iterate the directory and post the directories and files to the - // ports. - errno = 0; - dirent* entry = readdir(reinterpret_cast(lister_)); - if (entry != nullptr) { - if (!listing->path_buffer().Add(entry->d_name)) { - done_ = true; - return kListError; - } - switch (entry->d_type) { - case DT_DIR: - if ((strcmp(entry->d_name, ".") == 0) || - (strcmp(entry->d_name, "..") == 0)) { - return Next(listing); - } - return kListDirectory; - case DT_BLK: - case DT_CHR: - case DT_FIFO: - case DT_SOCK: - case DT_REG: - return kListFile; - case DT_LNK: - if (!listing->follow_links()) { - return kListLink; - } - // Else fall through to next case. - FALL_THROUGH; - case DT_UNKNOWN: { - // On some file systems the entry type is not determined by - // readdir. For those and for links we use stat to determine - // the actual entry type. Notice that stat returns the type of - // the file pointed to. - NamespaceScope ns(listing->namespc(), - listing->path_buffer().AsString()); - struct stat entry_info; - int stat_success; - stat_success = TEMP_FAILURE_RETRY( - fstatat(ns.fd(), ns.path(), &entry_info, AT_SYMLINK_NOFOLLOW)); - if (stat_success == -1) { - return kListError; - } - if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { - // Check to see if we are in a loop created by a symbolic link. - LinkList current_link = {entry_info.st_dev, entry_info.st_ino, link_}; - LinkList* previous = link_; - while (previous != nullptr) { - if ((previous->dev == current_link.dev) && - (previous->ino == current_link.ino)) { - // Report the looping link as a link, rather than following it. - return kListLink; - } - previous = previous->next; - } - stat_success = - TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), &entry_info, 0)); - if (stat_success == -1 || (S_IFMT & entry_info.st_mode) == 0) { - // Report a broken link as a link, even if follow_links is true. - // A symbolic link can potentially point to an anon_inode. For - // example, an epoll file descriptor will have a symbolic link whose - // content is the string anon_inode:[eventpoll]. In this case, the - // target doesn't belong to any regular file category. - return kListLink; - } - if (S_ISDIR(entry_info.st_mode)) { - // Recurse into the subdirectory with current_link added to the - // linked list of seen file system links. - link_ = new LinkList(current_link); - if ((strcmp(entry->d_name, ".") == 0) || - (strcmp(entry->d_name, "..") == 0)) { - return Next(listing); - } - return kListDirectory; - } - } - if (S_ISDIR(entry_info.st_mode)) { - if ((strcmp(entry->d_name, ".") == 0) || - (strcmp(entry->d_name, "..") == 0)) { - return Next(listing); - } - return kListDirectory; - } else if (S_ISLNK(entry_info.st_mode)) { - return kListLink; - } else { - // Regular files, character devices, block devices, fifos, sockets and - // unknown types are all considered as files. - return kListFile; - } - } - - default: - // We should have covered all the bases. If not, let's get an error. - FATAL("Unexpected d_type: %d\n", entry->d_type); - return kListError; - } - } - done_ = true; - - if (errno != 0) { - return kListError; - } - - return kListDone; -} - -DirectoryListingEntry::~DirectoryListingEntry() { - ResetLink(); - if (lister_ != 0) { - // This also closes fd_. - VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast(lister_))); - } -} - -void DirectoryListingEntry::ResetLink() { - if ((link_ != nullptr) && - ((parent_ == nullptr) || (parent_->link_ != link_))) { - delete link_; - link_ = nullptr; - } - if (parent_ != nullptr) { - link_ = parent_->link_; - } -} - -static bool DeleteRecursively(int dirfd, PathBuffer* path); - -static bool DeleteFile(int dirfd, char* file_name, PathBuffer* path) { - return path->Add(file_name) && - (NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), 0)) == 0); -} - -static bool DeleteDir(int dirfd, char* dir_name, PathBuffer* path) { - if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { - return true; - } - return path->Add(dir_name) && DeleteRecursively(dirfd, path); -} - -static bool DeleteRecursively(int dirfd, PathBuffer* path) { - // Do not recurse into links for deletion. Instead delete the link. - // If it's a file, delete it. - struct stat st; - if (TEMP_FAILURE_RETRY( - fstatat(dirfd, path->AsString(), &st, AT_SYMLINK_NOFOLLOW)) == -1) { - return false; - } else if (!S_ISDIR(st.st_mode)) { - return (NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), 0)) == 0); - } - - if (!path->Add(File::PathSeparator())) { - return false; - } - - // Not a link. Attempt to open as a directory and recurse into the - // directory. - const int fd = - TEMP_FAILURE_RETRY(openat(dirfd, path->AsString(), O_DIRECTORY)); - if (fd < 0) { - return false; - } - DIR* dir_pointer; - do { - dir_pointer = fdopendir(fd); - } while ((dir_pointer == nullptr) && (errno == EINTR)); - if (dir_pointer == nullptr) { - FDUtils::SaveErrorAndClose(fd); - return false; - } - - // Iterate the directory and delete all files and directories. - int path_length = path->length(); - while (true) { - // In case `readdir()` returns `nullptr` we distinguish between - // end-of-stream and error by looking if `errno` was updated. - errno = 0; - // In glibc 2.24+, readdir_r is deprecated. - // According to the man page for readdir: - // "readdir(3) is not required to be thread-safe. However, in modern - // implementations (including the glibc implementation), concurrent calls to - // readdir(3) that specify different directory streams are thread-safe." - dirent* entry = readdir(dir_pointer); - if (entry == nullptr) { - // Failed to read next directory entry. - if (errno != 0) { - break; - } - // End of directory. - int status = NO_RETRY_EXPECTED(closedir(dir_pointer)); - if (status != 0) { - return false; - } - status = - NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), AT_REMOVEDIR)); - return status == 0; - } - bool ok = false; - switch (entry->d_type) { - case DT_DIR: - ok = DeleteDir(dirfd, entry->d_name, path); - break; - case DT_BLK: - case DT_CHR: - case DT_FIFO: - case DT_SOCK: - case DT_REG: - case DT_LNK: - // Treat all links as files. This will delete the link which - // is what we want no matter if the link target is a file or a - // directory. - ok = DeleteFile(dirfd, entry->d_name, path); - break; - case DT_UNKNOWN: { - if (!path->Add(entry->d_name)) { - break; - } - // On some file systems the entry type is not determined by - // readdir. For those we use lstat to determine the entry - // type. - struct stat entry_info; - if (TEMP_FAILURE_RETRY(fstatat(dirfd, path->AsString(), &entry_info, - AT_SYMLINK_NOFOLLOW)) == -1) { - break; - } - path->Reset(path_length); - if (S_ISDIR(entry_info.st_mode)) { - ok = DeleteDir(dirfd, entry->d_name, path); - } else { - // Treat links as files. This will delete the link which is - // what we want no matter if the link target is a file or a - // directory. - ok = DeleteFile(dirfd, entry->d_name, path); - } - break; - } - default: - // We should have covered all the bases. If not, let's get an error. - FATAL("Unexpected d_type: %d\n", entry->d_type); - break; - } - if (!ok) { - break; - } - path->Reset(path_length); - } - // Only happens if an error. - ASSERT(errno != 0); - int err = errno; - VOID_NO_RETRY_EXPECTED(closedir(dir_pointer)); - errno = err; - return false; -} - -Directory::ExistsResult Directory::Exists(Namespace* namespc, - const char* dir_name) { - NamespaceScope ns(namespc, dir_name); - struct stat entry_info; - int success = TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), &entry_info, 0)); - if (success == 0) { - if (S_ISDIR(entry_info.st_mode)) { - return EXISTS; - } else { - // An OSError may be constructed based on the return value of this - // function, so set errno to something that makes sense. - errno = ENOTDIR; - return DOES_NOT_EXIST; - } - } else { - if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || - (errno == ENOMEM) || (errno == EOVERFLOW)) { - // Search permissions denied for one of the directories in the - // path or a low level error occurred. We do not know if the - // directory exists. - return UNKNOWN; - } - ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || - (errno == ENOTDIR)); - return DOES_NOT_EXIST; - } -} - -char* Directory::CurrentNoScope() { - // Android's getcwd adheres closely to the POSIX standard. It won't - // allocate memory. We need to make our own copy. - char buffer[PATH_MAX]; - if (getcwd(buffer, PATH_MAX) == nullptr) { - return nullptr; - } - - return strdup(buffer); -} - -bool Directory::Create(Namespace* namespc, const char* dir_name) { - NamespaceScope ns(namespc, dir_name); - // Create the directory with the permissions specified by the - // process umask. - const int result = NO_RETRY_EXPECTED(mkdirat(ns.fd(), ns.path(), 0777)); - // If the directory already exists, treat it as a success. - if ((result == -1) && (errno == EEXIST)) { - return (Exists(namespc, dir_name) == EXISTS); - } - return (result == 0); -} - -const char* Directory::SystemTemp(Namespace* namespc) { - if (Directory::system_temp_path_override_ != nullptr) { - return DartUtils::ScopedCopyCString(Directory::system_temp_path_override_); - } - // Android does not have a /tmp directory. A partial substitute, - // suitable for bring-up work and tests, is to create a tmp - // directory in /data/local/tmp. - // - // TODO(4413): In the long run, when running in an application we should - // probably use the appropriate directory from the Android API, - // probably what File.createTempFile uses. - const char* kAndroidTempDir = "/data/local/tmp"; - struct stat st; - if (stat(kAndroidTempDir, &st) != 0) { - mkdir(kAndroidTempDir, 0777); - } - return kAndroidTempDir; -} - -// Returns a new, unused directory name, adding characters to the end -// of prefix. Creates the directory with the permissions specified -// by the process umask. -// The return value is Dart_ScopeAllocated. -const char* Directory::CreateTemp(Namespace* namespc, const char* prefix) { - PathBuffer path; - const int firstchar = 'A'; - const int numchars = 'Z' - 'A' + 1; - uint8_t random_bytes[7]; - - // mkdtemp doesn't have an "at" variant, so we have to simulate it. - if (!path.Add(prefix)) { - return nullptr; - } - intptr_t prefix_length = path.length(); - while (true) { - Crypto::GetRandomBytes(6, random_bytes); - for (intptr_t i = 0; i < 6; i++) { - random_bytes[i] = (random_bytes[i] % numchars) + firstchar; - } - random_bytes[6] = '\0'; - if (!path.Add(reinterpret_cast(random_bytes))) { - return nullptr; - } - NamespaceScope ns(namespc, path.AsString()); - const int result = NO_RETRY_EXPECTED(mkdirat(ns.fd(), ns.path(), 0777)); - if (result == 0) { - return path.AsScopedString(); - } else if (errno == EEXIST) { - path.Reset(prefix_length); - } else { - return nullptr; - } - } -} - -bool Directory::Delete(Namespace* namespc, - const char* dir_name, - bool recursive) { - NamespaceScope ns(namespc, dir_name); - if (!recursive) { - if ((File::GetType(namespc, dir_name, false) == File::kIsLink) && - (File::GetType(namespc, dir_name, true) == File::kIsDirectory)) { - return NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0; - } - return NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), AT_REMOVEDIR)) == 0; - } else { - PathBuffer path; - if (!path.Add(ns.path())) { - return false; - } - return DeleteRecursively(ns.fd(), &path); - } -} - -bool Directory::Rename(Namespace* namespc, - const char* old_path, - const char* new_path) { - ExistsResult exists = Exists(namespc, old_path); - if (exists != EXISTS) { - return false; - } - NamespaceScope oldns(namespc, old_path); - NamespaceScope newns(namespc, new_path); - return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(), - newns.path())) == 0); -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc index 755bae9b648..ddfed623368 100644 --- a/runtime/bin/directory_linux.cc +++ b/runtime/bin/directory_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/directory.h" @@ -75,7 +75,7 @@ void PathBuffer::Reset(intptr_t new_length) { // A linked list of symbolic links, with their unique file system identifiers. // These are scanned to detect loops while doing a recursive directory listing. struct LinkList { - dev_t dev; + decltype(stat64::st_dev) dev; ino64_t ino; LinkList* next; }; @@ -414,13 +414,21 @@ bool Directory::Create(Namespace* namespc, const char* dir_name) { } const char* Directory::SystemTemp(Namespace* namespc) { + if (Directory::system_temp_path_override_ != nullptr) { + return DartUtils::ScopedCopyCString(Directory::system_temp_path_override_); + } + PathBuffer path; const char* temp_dir = getenv("TMPDIR"); if (temp_dir == nullptr) { temp_dir = getenv("TMP"); } if (temp_dir == nullptr) { +#if defined(DART_HOST_OS_ANDROID) + temp_dir = "/data/local/tmp"; +#else temp_dir = "/tmp"; +#endif } NamespaceScope ns(namespc, temp_dir); if (!path.Add(ns.path())) { @@ -507,4 +515,4 @@ bool Directory::Rename(Namespace* namespc, } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h index c4a70cb45e9..d35fc539ab1 100644 --- a/runtime/bin/eventhandler.h +++ b/runtime/bin/eventhandler.h @@ -585,11 +585,9 @@ class DescriptorInfoMultipleMixin : public DI { } // namespace dart // The event handler delegation class is OS specific. -#if defined(DART_HOST_OS_ANDROID) -#include "bin/eventhandler_android.h" -#elif defined(DART_HOST_OS_FUCHSIA) +#if defined(DART_HOST_OS_FUCHSIA) #include "bin/eventhandler_fuchsia.h" -#elif defined(DART_HOST_OS_LINUX) +#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/eventhandler_linux.h" #elif defined(DART_HOST_OS_MACOS) #include "bin/eventhandler_macos.h" diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc deleted file mode 100644 index 00295d1a278..00000000000 --- a/runtime/bin/eventhandler_android.cc +++ /dev/null @@ -1,443 +0,0 @@ -// 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_ANDROID) - -#include "bin/eventhandler.h" -#include "bin/eventhandler_android.h" - -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#include "bin/dartutils.h" -#include "bin/fdutils.h" -#include "bin/lockers.h" -#include "bin/process.h" -#include "bin/socket.h" -#include "bin/thread.h" -#include "bin/utils.h" -#include "platform/hashmap.h" -#include "platform/syslog.h" -#include "platform/utils.h" - -// Android doesn't define EPOLLRDHUP. -#if !defined(EPOLLRDHUP) -#define EPOLLRDHUP 0x2000 -#endif // !defined(EPOLLRDHUP) - -namespace dart { -namespace bin { - -intptr_t DescriptorInfo::GetPollEvents() { - // Do not ask for EPOLLERR and EPOLLHUP explicitly as they are - // triggered anyway. - intptr_t events = 0; - if ((Mask() & (1 << kInEvent)) != 0) { - events |= EPOLLIN; - } - if ((Mask() & (1 << kOutEvent)) != 0) { - events |= EPOLLOUT; - } - return events; -} - -// Unregister the file descriptor for a DescriptorInfo structure with -// epoll. -static void RemoveFromEpollInstance(intptr_t epoll_fd_, DescriptorInfo* di) { - VOID_NO_RETRY_EXPECTED( - epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, di->fd(), nullptr)); -} - -static void AddToEpollInstance(intptr_t epoll_fd_, DescriptorInfo* di) { - struct epoll_event event; - event.events = EPOLLRDHUP | di->GetPollEvents(); - if (!di->IsListeningSocket()) { - event.events |= EPOLLET; - } - event.data.ptr = di; - int status = - NO_RETRY_EXPECTED(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, di->fd(), &event)); - if (status == -1) { - // TODO(dart:io): Verify that the dart end is handling this correctly. - - // Epoll does not accept the file descriptor. It could be due to - // already closed file descriptor, or unsupported devices, such - // as /dev/null. In such case, mark the file descriptor as closed, - // so dart will handle it accordingly. - di->NotifyAllDartPorts(1 << kCloseEvent); - } -} - -EventHandlerImplementation::EventHandlerImplementation() - : socket_map_(&SimpleHashMap::SamePointerValue, 16) { - intptr_t result; - result = NO_RETRY_EXPECTED(pipe(interrupt_fds_)); - if (result != 0) { - FATAL("Pipe creation failed"); - } - if (!FDUtils::SetNonBlocking(interrupt_fds_[0])) { - FATAL("Failed to set pipe fd non blocking\n"); - } - if (!FDUtils::SetCloseOnExec(interrupt_fds_[0])) { - FATAL("Failed to set pipe fd close on exec\n"); - } - if (!FDUtils::SetCloseOnExec(interrupt_fds_[1])) { - FATAL("Failed to set pipe fd close on exec\n"); - } - shutdown_ = false; - // The initial size passed to epoll_create is ignored on newer (>= 2.6.8) - // Linux versions - const int kEpollInitialSize = 64; - epoll_fd_ = NO_RETRY_EXPECTED(epoll_create(kEpollInitialSize)); - if (epoll_fd_ == -1) { - FATAL("Failed creating epoll file descriptor: %i", errno); - } - if (!FDUtils::SetCloseOnExec(epoll_fd_)) { - FATAL("Failed to set epoll fd close on exec\n"); - } - // Register the interrupt_fd with the epoll instance. - struct epoll_event event; - event.events = EPOLLIN; - event.data.ptr = nullptr; - int status = NO_RETRY_EXPECTED( - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupt_fds_[0], &event)); - if (status == -1) { - FATAL("Failed adding interrupt fd to epoll instance"); - } -} - -static void DeleteDescriptorInfo(void* info) { - DescriptorInfo* di = reinterpret_cast(info); - di->Close(); - delete di; -} - -EventHandlerImplementation::~EventHandlerImplementation() { - socket_map_.Clear(DeleteDescriptorInfo); - close(epoll_fd_); - close(interrupt_fds_[0]); - close(interrupt_fds_[1]); -} - -void EventHandlerImplementation::UpdateEpollInstance(intptr_t old_mask, - DescriptorInfo* di) { - intptr_t new_mask = di->Mask(); - if ((old_mask != 0) && (new_mask == 0)) { - RemoveFromEpollInstance(epoll_fd_, di); - } else if ((old_mask == 0) && (new_mask != 0)) { - AddToEpollInstance(epoll_fd_, di); - } else if ((old_mask != 0) && (new_mask != 0) && (old_mask != new_mask)) { - ASSERT(!di->IsListeningSocket()); - RemoveFromEpollInstance(epoll_fd_, di); - AddToEpollInstance(epoll_fd_, di); - } -} - -DescriptorInfo* EventHandlerImplementation::GetDescriptorInfo( - intptr_t fd, - bool is_listening) { - ASSERT(fd >= 0); - SimpleHashMap::Entry* entry = socket_map_.Lookup( - GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true); - ASSERT(entry != nullptr); - DescriptorInfo* di = reinterpret_cast(entry->value); - if (di == nullptr) { - // If there is no data in the hash map for this file descriptor a - // new DescriptorInfo for the file descriptor is inserted. - if (is_listening) { - di = new DescriptorInfoMultiple(fd); - } else { - di = new DescriptorInfoSingle(fd); - } - entry->value = di; - } - ASSERT(fd == di->fd()); - return di; -} - -void EventHandlerImplementation::WakeupHandler(intptr_t id, - Dart_Port dart_port, - int64_t data) { - InterruptMessage msg; - msg.id = id; - msg.dart_port = dart_port; - msg.data = data; - // WriteToBlocking will write up to 512 bytes atomically, and since our msg - // is smaller than 512, we don't need a thread lock. - // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'. - ASSERT(kInterruptMessageSize < PIPE_BUF); - intptr_t result = - FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize); - if (result != kInterruptMessageSize) { - if (result == -1) { - FATAL("Interrupt message failure: %s", strerror(errno)); - } else { - FATAL("Interrupt message failure: expected to write %" Pd - " bytes, but wrote %" Pd ".", - kInterruptMessageSize, result); - } - } -} - -void EventHandlerImplementation::HandleInterruptFd() { - const intptr_t MAX_MESSAGES = kInterruptMessageSize; - InterruptMessage msg[MAX_MESSAGES]; - ssize_t bytes = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER( - read(interrupt_fds_[0], msg, MAX_MESSAGES * kInterruptMessageSize)); - for (ssize_t i = 0; i < bytes / kInterruptMessageSize; i++) { - if (msg[i].id == kTimerId) { - timeout_queue_.UpdateTimeout(msg[i].dart_port, msg[i].data); - } else if (msg[i].id == kShutdownId) { - shutdown_ = true; - } else { - ASSERT((msg[i].data & COMMAND_MASK) != 0); - Socket* socket = reinterpret_cast(msg[i].id); - RefCntReleaseScope rs(socket); - if (socket->fd() == -1) { - continue; - } - DescriptorInfo* di = - GetDescriptorInfo(socket->fd(), IS_LISTENING_SOCKET(msg[i].data)); - if (IS_COMMAND(msg[i].data, kShutdownReadCommand)) { - ASSERT(!di->IsListeningSocket()); - // Close the socket for reading. - VOID_NO_RETRY_EXPECTED(shutdown(di->fd(), SHUT_RD)); - } else if (IS_COMMAND(msg[i].data, kShutdownWriteCommand)) { - ASSERT(!di->IsListeningSocket()); - // Close the socket for writing. - VOID_NO_RETRY_EXPECTED(shutdown(di->fd(), SHUT_WR)); - } else if (IS_COMMAND(msg[i].data, kCloseCommand)) { - // Close the socket and free system resources and move on to next - // message. - if (IS_SIGNAL_SOCKET(msg[i].data)) { - Process::ClearSignalHandlerByFd(di->fd(), socket->isolate_port()); - } - intptr_t old_mask = di->Mask(); - Dart_Port port = msg[i].dart_port; - if (port != ILLEGAL_PORT) { - di->RemovePort(port); - } - intptr_t new_mask = di->Mask(); - UpdateEpollInstance(old_mask, di); - - intptr_t fd = di->fd(); - if (di->IsListeningSocket()) { - // We only close the socket file descriptor from the operating - // system if there are no other dart socket objects which - // are listening on the same (address, port) combination. - ListeningSocketRegistry* registry = - ListeningSocketRegistry::Instance(); - - MutexLocker locker(registry->mutex()); - - if (registry->CloseSafe(socket)) { - ASSERT(new_mask == 0); - socket_map_.Remove(GetHashmapKeyFromFd(fd), - GetHashmapHashFromFd(fd)); - di->Close(); - delete di; - } - socket->CloseFd(); - } else { - ASSERT(new_mask == 0); - socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd)); - di->Close(); - delete di; - socket->CloseFd(); - } - - DartUtils::PostInt32(port, 1 << kDestroyedEvent); - } else if (IS_COMMAND(msg[i].data, kReturnTokenCommand)) { - int count = TOKEN_COUNT(msg[i].data); - intptr_t old_mask = di->Mask(); - di->ReturnTokens(msg[i].dart_port, count); - UpdateEpollInstance(old_mask, di); - } else if (IS_COMMAND(msg[i].data, kSetEventMaskCommand)) { - // `events` can only have kInEvent/kOutEvent flags set. - intptr_t events = msg[i].data & EVENT_MASK; - ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent))); - - intptr_t old_mask = di->Mask(); - di->SetPortAndMask(msg[i].dart_port, msg[i].data & EVENT_MASK); - UpdateEpollInstance(old_mask, di); - } else { - UNREACHABLE(); - } - } - } -} - -#ifdef DEBUG_POLL -static void PrintEventMask(intptr_t fd, intptr_t events) { - Syslog::Print("%d ", fd); - if ((events & EPOLLIN) != 0) { - Syslog::Print("EPOLLIN "); - } - if ((events & EPOLLPRI) != 0) { - Syslog::Print("EPOLLPRI "); - } - if ((events & EPOLLOUT) != 0) { - Syslog::Print("EPOLLOUT "); - } - if ((events & EPOLLERR) != 0) { - Syslog::Print("EPOLLERR "); - } - if ((events & EPOLLHUP) != 0) { - Syslog::Print("EPOLLHUP "); - } - if ((events & EPOLLRDHUP) != 0) { - Syslog::Print("EPOLLRDHUP "); - } - int all_events = - EPOLLIN | EPOLLPRI | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLRDHUP; - if ((events & ~all_events) != 0) { - Syslog::Print("(and %08x) ", events & ~all_events); - } - Syslog::Print("(available %d) ", FDUtils::AvailableBytes(fd)); - - Syslog::Print("\n"); -} -#endif - -intptr_t EventHandlerImplementation::GetPollEvents(intptr_t events, - DescriptorInfo* di) { -#ifdef DEBUG_POLL - PrintEventMask(di->fd(), events); -#endif - if ((events & EPOLLERR) != 0) { - // Return error only if EPOLLIN is present. - return ((events & EPOLLIN) != 0) ? (1 << kErrorEvent) : 0; - } - intptr_t event_mask = 0; - if ((events & EPOLLIN) != 0) { - event_mask |= (1 << kInEvent); - } - if ((events & EPOLLOUT) != 0) { - event_mask |= (1 << kOutEvent); - } - if ((events & (EPOLLHUP | EPOLLRDHUP)) != 0) { - event_mask |= (1 << kCloseEvent); - } - return event_mask; -} - -void EventHandlerImplementation::HandleEvents(struct epoll_event* events, - int size) { - bool interrupt_seen = false; - for (int i = 0; i < size; i++) { - if (events[i].data.ptr == nullptr) { - interrupt_seen = true; - } else { - DescriptorInfo* di = - reinterpret_cast(events[i].data.ptr); - const intptr_t old_mask = di->Mask(); - const intptr_t event_mask = GetPollEvents(events[i].events, di); - if ((event_mask & (1 << kErrorEvent)) != 0) { - di->NotifyAllDartPorts(event_mask); - UpdateEpollInstance(old_mask, di); - } else if (event_mask != 0) { - Dart_Port port = di->NextNotifyDartPort(event_mask); - ASSERT(port != 0); - UpdateEpollInstance(old_mask, di); - DartUtils::PostInt32(port, event_mask); - } - } - } - if (interrupt_seen) { - // Handle after socket events, so we avoid closing a socket before we handle - // the current events. - HandleInterruptFd(); - } -} - -int64_t EventHandlerImplementation::GetTimeout() { - if (!timeout_queue_.HasTimeout()) { - return kInfinityTimeout; - } - int64_t millis = - timeout_queue_.CurrentTimeout() - TimerUtils::GetCurrentMonotonicMillis(); - return (millis < 0) ? 0 : millis; -} - -void EventHandlerImplementation::HandleTimeout() { - if (timeout_queue_.HasTimeout()) { - int64_t millis = timeout_queue_.CurrentTimeout() - - TimerUtils::GetCurrentMonotonicMillis(); - if (millis <= 0) { - DartUtils::PostNull(timeout_queue_.CurrentPort()); - timeout_queue_.RemoveCurrent(); - } - } -} - -void EventHandlerImplementation::Poll(uword args) { - ThreadSignalBlocker signal_blocker(SIGPROF); - const intptr_t kMaxEvents = 16; - struct epoll_event events[kMaxEvents]; - EventHandler* handler = reinterpret_cast(args); - EventHandlerImplementation* handler_impl = &handler->delegate_; - ASSERT(handler_impl != nullptr); - - while (!handler_impl->shutdown_) { - int64_t millis = handler_impl->GetTimeout(); - ASSERT((millis == kInfinityTimeout) || (millis >= 0)); - if (millis > kMaxInt32) { - millis = kMaxInt32; - } - intptr_t result = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER( - epoll_wait(handler_impl->epoll_fd_, events, kMaxEvents, millis)); - ASSERT(EAGAIN == EWOULDBLOCK); - if (result == -1) { - if (errno != EWOULDBLOCK) { - perror("Poll failed"); - } - } else { - handler_impl->HandleTimeout(); - handler_impl->HandleEvents(events, result); - } - } - DEBUG_ASSERT(ReferenceCounted::instances() == 0); - handler->NotifyShutdownDone(); -} - -void EventHandlerImplementation::Start(EventHandler* handler) { - int result = - Thread::Start("dart:io EventHandler", &EventHandlerImplementation::Poll, - reinterpret_cast(handler)); - if (result != 0) { - FATAL("Failed to start event handler thread %d", result); - } -} - -void EventHandlerImplementation::Shutdown() { - SendData(kShutdownId, 0, 0); -} - -void EventHandlerImplementation::SendData(intptr_t id, - Dart_Port dart_port, - int64_t data) { - WakeupHandler(id, dart_port, data); -} - -void* EventHandlerImplementation::GetHashmapKeyFromFd(intptr_t fd) { - // The hashmap does not support keys with value 0. - return reinterpret_cast(fd + 1); -} - -uint32_t EventHandlerImplementation::GetHashmapHashFromFd(intptr_t fd) { - // The hashmap does not support keys with value 0. - return dart::Utils::WordHash(fd + 1); -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/eventhandler_android.h b/runtime/bin/eventhandler_android.h deleted file mode 100644 index d8cceca1706..00000000000 --- a/runtime/bin/eventhandler_android.h +++ /dev/null @@ -1,100 +0,0 @@ -// 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. - -#ifndef RUNTIME_BIN_EVENTHANDLER_ANDROID_H_ -#define RUNTIME_BIN_EVENTHANDLER_ANDROID_H_ - -#if !defined(RUNTIME_BIN_EVENTHANDLER_H_) -#error Do not include eventhandler_android.h directly; -#error use eventhandler.h instead. -#endif - -#include -#include -#include -#include - -#include "platform/hashmap.h" -#include "platform/signal_blocker.h" - -namespace dart { -namespace bin { - -class DescriptorInfo : public DescriptorInfoBase { - public: - explicit DescriptorInfo(intptr_t fd) : DescriptorInfoBase(fd) {} - - virtual ~DescriptorInfo() {} - - intptr_t GetPollEvents(); - - virtual void Close() { - close(fd_); - fd_ = -1; - } - - private: - DISALLOW_COPY_AND_ASSIGN(DescriptorInfo); -}; - -class DescriptorInfoSingle : public DescriptorInfoSingleMixin { - public: - explicit DescriptorInfoSingle(intptr_t fd) - : DescriptorInfoSingleMixin(fd, false) {} - virtual ~DescriptorInfoSingle() {} - - private: - DISALLOW_COPY_AND_ASSIGN(DescriptorInfoSingle); -}; - -class DescriptorInfoMultiple - : public DescriptorInfoMultipleMixin { - public: - explicit DescriptorInfoMultiple(intptr_t fd) - : DescriptorInfoMultipleMixin(fd, false) {} - virtual ~DescriptorInfoMultiple() {} - - private: - DISALLOW_COPY_AND_ASSIGN(DescriptorInfoMultiple); -}; - -class EventHandlerImplementation { - public: - EventHandlerImplementation(); - ~EventHandlerImplementation(); - - void UpdateEpollInstance(intptr_t old_mask, DescriptorInfo* di); - - // Gets the socket data structure for a given file - // descriptor. Creates a new one if one is not found. - DescriptorInfo* GetDescriptorInfo(intptr_t fd, bool is_listening); - void SendData(intptr_t id, Dart_Port dart_port, int64_t data); - void Start(EventHandler* handler); - void Shutdown(); - - private: - int64_t GetTimeout(); - void HandleEvents(struct epoll_event* events, int size); - void HandleTimeout(); - static void Poll(uword args); - void WakeupHandler(intptr_t id, Dart_Port dart_port, int64_t data); - void HandleInterruptFd(); - void SetPort(intptr_t fd, Dart_Port dart_port, intptr_t mask); - intptr_t GetPollEvents(intptr_t events, DescriptorInfo* di); - static void* GetHashmapKeyFromFd(intptr_t fd); - static uint32_t GetHashmapHashFromFd(intptr_t fd); - - SimpleHashMap socket_map_; - TimeoutQueue timeout_queue_; - bool shutdown_; - int interrupt_fds_[2]; - int epoll_fd_; - - DISALLOW_COPY_AND_ASSIGN(EventHandlerImplementation); -}; - -} // namespace bin -} // namespace dart - -#endif // RUNTIME_BIN_EVENTHANDLER_ANDROID_H_ diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc index bbfa21f2be8..f281d497a20 100644 --- a/runtime/bin/eventhandler_linux.cc +++ b/runtime/bin/eventhandler_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/eventhandler.h" #include "bin/eventhandler_linux.h" @@ -444,4 +444,4 @@ uint32_t EventHandlerImplementation::GetHashmapHashFromFd(intptr_t fd) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/fdutils_android.cc b/runtime/bin/fdutils_android.cc deleted file mode 100644 index ad30d28ff99..00000000000 --- a/runtime/bin/fdutils_android.cc +++ /dev/null @@ -1,142 +0,0 @@ -// 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_ANDROID) - -#include "bin/fdutils.h" - -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#include "platform/signal_blocker.h" - -namespace dart { -namespace bin { - -bool FDUtils::SetCloseOnExec(intptr_t fd) { - intptr_t status; - status = NO_RETRY_EXPECTED(fcntl(fd, F_GETFD)); - if (status < 0) { - perror("fcntl(F_GETFD) failed"); - return false; - } - status |= FD_CLOEXEC; - if (NO_RETRY_EXPECTED(fcntl(fd, F_SETFD, status)) < 0) { - perror("fcntl(F_SETFD, FD_CLOEXEC) failed"); - return false; - } - return true; -} - -static bool SetBlockingHelper(intptr_t fd, bool blocking) { - intptr_t status; - status = NO_RETRY_EXPECTED(fcntl(fd, F_GETFL)); - if (status < 0) { - perror("fcntl(F_GETFL) failed"); - return false; - } - status = blocking ? (status & ~O_NONBLOCK) : (status | O_NONBLOCK); - if (NO_RETRY_EXPECTED(fcntl(fd, F_SETFL, status)) < 0) { - perror("fcntl(F_SETFL, O_NONBLOCK) failed"); - return false; - } - return true; -} - -bool FDUtils::SetNonBlocking(intptr_t fd) { - return SetBlockingHelper(fd, false); -} - -bool FDUtils::SetBlocking(intptr_t fd) { - return SetBlockingHelper(fd, true); -} - -bool FDUtils::IsBlocking(intptr_t fd, bool* is_blocking) { - intptr_t status; - status = NO_RETRY_EXPECTED(fcntl(fd, F_GETFL)); - if (status < 0) { - return false; - } - *is_blocking = (status & O_NONBLOCK) == 0; - return true; -} - -intptr_t FDUtils::AvailableBytes(intptr_t fd) { - int available; // ioctl for FIONREAD expects an 'int*' argument. - int result = NO_RETRY_EXPECTED(ioctl(fd, FIONREAD, &available)); - if (result < 0) { - return result; - } - ASSERT(available >= 0); - return static_cast(available); -} - -ssize_t FDUtils::ReadFromBlocking(int fd, void* buffer, size_t count) { -#ifdef DEBUG - bool is_blocking = false; - ASSERT(FDUtils::IsBlocking(fd, &is_blocking)); - ASSERT(is_blocking); -#endif - size_t remaining = count; - char* buffer_pos = reinterpret_cast(buffer); - while (remaining > 0) { - ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer_pos, remaining)); - if (bytes_read == 0) { - return count - remaining; - } else if (bytes_read == -1) { - ASSERT(EAGAIN == EWOULDBLOCK); - // Error code EWOULDBLOCK should only happen for non blocking - // file descriptors. - ASSERT(errno != EWOULDBLOCK); - return -1; - } else { - ASSERT(bytes_read > 0); - remaining -= bytes_read; - buffer_pos += bytes_read; - } - } - return count; -} - -ssize_t FDUtils::WriteToBlocking(int fd, const void* buffer, size_t count) { -#ifdef DEBUG - bool is_blocking = false; - ASSERT(FDUtils::IsBlocking(fd, &is_blocking)); - ASSERT(is_blocking); -#endif - size_t remaining = count; - char* buffer_pos = const_cast(reinterpret_cast(buffer)); - while (remaining > 0) { - ssize_t bytes_written = - TEMP_FAILURE_RETRY(write(fd, buffer_pos, remaining)); - if (bytes_written == 0) { - return count - remaining; - } else if (bytes_written == -1) { - ASSERT(EAGAIN == EWOULDBLOCK); - // Error code EWOULDBLOCK should only happen for non blocking - // file descriptors. - ASSERT(errno != EWOULDBLOCK); - return -1; - } else { - ASSERT(bytes_written > 0); - remaining -= bytes_written; - buffer_pos += bytes_written; - } - } - return count; -} - -void FDUtils::SaveErrorAndClose(intptr_t fd) { - int err = errno; - close(fd); - errno = err; -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/fdutils_linux.cc b/runtime/bin/fdutils_linux.cc index f730ea6c595..c13a07b1b36 100644 --- a/runtime/bin/fdutils_linux.cc +++ b/runtime/bin/fdutils_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/fdutils.h" @@ -139,4 +139,4 @@ void FDUtils::SaveErrorAndClose(intptr_t fd) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc deleted file mode 100644 index 4b53ee21e86..00000000000 --- a/runtime/bin/file_android.cc +++ /dev/null @@ -1,793 +0,0 @@ -// 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_ANDROID) - -#include "bin/file.h" - -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#include "bin/builtin.h" -#include "bin/fdutils.h" -#include "bin/namespace.h" -#include "platform/signal_blocker.h" -#include "platform/syslog.h" -#include "platform/utils.h" - -namespace dart { -namespace bin { - -class FileHandle { - public: - explicit FileHandle(int fd) : fd_(fd) {} - ~FileHandle() {} - int fd() const { return fd_; } - void set_fd(int fd) { fd_ = fd; } - - private: - int fd_; - - DISALLOW_COPY_AND_ASSIGN(FileHandle); -}; - -File::~File() { - if (!IsClosed() && (handle_->fd() != STDOUT_FILENO) && - (handle_->fd() != STDERR_FILENO)) { - Close(); - } - delete handle_; -} - -void File::Close() { - ASSERT(handle_->fd() >= 0); - if (handle_->fd() == STDOUT_FILENO) { - // If stdout, redirect fd to /dev/null. - int null_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY)); - ASSERT(null_fd >= 0); - VOID_TEMP_FAILURE_RETRY(dup2(null_fd, handle_->fd())); - close(null_fd); - } else { - int err = close(handle_->fd()); - if (err != 0) { - const int kBufferSize = 1024; - char error_buf[kBufferSize]; - Syslog::PrintErr("%s\n", Utils::StrError(errno, error_buf, kBufferSize)); - } - } - handle_->set_fd(kClosedFd); -} - -intptr_t File::GetFD() { - return handle_->fd(); -} - -bool File::IsClosed() { - return handle_->fd() == kClosedFd; -} - -MappedMemory* File::Map(MapType type, - int64_t position, - int64_t length, - void* start) { - ASSERT(handle_->fd() >= 0); - ASSERT(length > 0); - void* hint = nullptr; - int prot = PROT_NONE; - int flags = MAP_PRIVATE; - switch (type) { - case kReadOnly: - prot = PROT_READ; - break; - case kReadExecute: - // Try to allocate near the VM's binary. - hint = reinterpret_cast(&Dart_Initialize); - prot = PROT_READ | PROT_EXEC; - break; - case kReadWrite: - prot = PROT_READ | PROT_WRITE; - break; - } - if (start != nullptr) { - hint = start; - flags |= MAP_FIXED; - } - void* addr = mmap(hint, length, prot, flags, handle_->fd(), position); - if (addr == MAP_FAILED) { - return nullptr; - } - return new MappedMemory(addr, length, /*should_unmap=*/start == nullptr); -} - -void MappedMemory::Unmap() { - int result = munmap(address_, size_); - ASSERT(result == 0); - address_ = nullptr; - size_ = 0; -} - -int64_t File::Read(void* buffer, int64_t num_bytes) { - ASSERT(handle_->fd() >= 0); - return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes)); -} - -int64_t File::Write(const void* buffer, int64_t num_bytes) { - ASSERT(handle_->fd() >= 0); - return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes)); -} - -bool File::VPrint(const char* format, va_list args) { - // Measure. - va_list measure_args; - va_copy(measure_args, args); - intptr_t len = vsnprintf(nullptr, 0, format, measure_args); - va_end(measure_args); - - char* buffer = reinterpret_cast(malloc(len + 1)); - - // Print. - va_list print_args; - va_copy(print_args, args); - vsnprintf(buffer, len + 1, format, print_args); - va_end(print_args); - - bool result = WriteFully(buffer, len); - free(buffer); - return result; -} - -int64_t File::Position() { - ASSERT(handle_->fd() >= 0); - return NO_RETRY_EXPECTED(lseek64(handle_->fd(), 0, SEEK_CUR)); -} - -bool File::SetPosition(int64_t position) { - ASSERT(handle_->fd() >= 0); - return NO_RETRY_EXPECTED(lseek64(handle_->fd(), position, SEEK_SET)) >= 0; -} - -bool File::Truncate(int64_t length) { - ASSERT(handle_->fd() >= 0); - return TEMP_FAILURE_RETRY(ftruncate(handle_->fd(), length) != -1); -} - -bool File::Flush() { - ASSERT(handle_->fd() >= 0); - return NO_RETRY_EXPECTED(fsync(handle_->fd()) != -1); -} - -bool File::Lock(File::LockType lock, int64_t start, int64_t end) { - ASSERT(handle_->fd() >= 0); - ASSERT((end == -1) || (end > start)); - struct flock fl; - switch (lock) { - case File::kLockUnlock: - fl.l_type = F_UNLCK; - break; - case File::kLockShared: - case File::kLockBlockingShared: - fl.l_type = F_RDLCK; - break; - case File::kLockExclusive: - case File::kLockBlockingExclusive: - fl.l_type = F_WRLCK; - break; - default: - return false; - } - fl.l_whence = SEEK_SET; - fl.l_start = start; - fl.l_len = end == -1 ? 0 : end - start; - int cmd = F_SETLK; - if ((lock == File::kLockBlockingShared) || - (lock == File::kLockBlockingExclusive)) { - cmd = F_SETLKW; - } - return TEMP_FAILURE_RETRY(fcntl(handle_->fd(), cmd, &fl)) != -1; -} - -int64_t File::Length() { - ASSERT(handle_->fd() >= 0); - struct stat st; - if (NO_RETRY_EXPECTED(fstat(handle_->fd(), &st)) == 0) { - return st.st_size; - } - return -1; -} - -File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) { - UNREACHABLE(); - return nullptr; -} - -File* File::OpenFD(int fd) { - return new File(new FileHandle(fd)); -} - -File* File::Open(Namespace* namespc, const char* name, FileOpenMode mode) { - NamespaceScope ns(namespc, name); - // Report errors for non-regular files. - struct stat st; - if (TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), &st, 0)) == 0) { - // Only accept regular files, character devices, and pipes. - if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) { - errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT; - return nullptr; - } - } - int flags = O_RDONLY; - if ((mode & kWrite) != 0) { - ASSERT((mode & kWriteOnly) == 0); - flags = (O_RDWR | O_CREAT); - } - if ((mode & kWriteOnly) != 0) { - ASSERT((mode & kWrite) == 0); - flags = (O_WRONLY | O_CREAT); - } - if ((mode & kTruncate) != 0) { - flags = flags | O_TRUNC; - } - flags |= O_CLOEXEC; - const int fd = TEMP_FAILURE_RETRY(openat(ns.fd(), ns.path(), flags, 0666)); - if (fd < 0) { - return nullptr; - } - if ((((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) || - (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) { - int64_t position = NO_RETRY_EXPECTED(lseek(fd, 0, SEEK_END)); - if (position < 0) { - return nullptr; - } - } - return new File(new FileHandle(fd)); -} - -Utils::CStringUniquePtr File::UriToPath(const char* uri) { - const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0) - ? uri + 7 : uri; - UriDecoder uri_decoder(path); - if (uri_decoder.decoded() == nullptr) { - errno = EINVAL; - return Utils::CreateCStringUniquePtr(nullptr); - } - return Utils::CreateCStringUniquePtr(strdup(uri_decoder.decoded())); -} - -File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) { - auto path = UriToPath(uri); - if (path == nullptr) { - return nullptr; - } - return File::Open(namespc, path.get(), mode); -} - -File* File::OpenStdio(int fd) { - return new File(new FileHandle(fd)); -} - -bool File::Exists(Namespace* namespc, const char* name) { - NamespaceScope ns(namespc, name); - struct stat st; - if (TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), &st, 0)) == 0) { - // Everything but a directory and a link is a file to Dart. - return !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode); - } else { - return false; - } -} - -bool File::ExistsUri(Namespace* namespc, const char* uri) { - auto path = UriToPath(uri); - if (path == nullptr) { - return false; - } - return File::Exists(namespc, path.get()); -} - -bool File::Create(Namespace* namespc, const char* name, bool exclusive) { - NamespaceScope ns(namespc, name); - int flags = O_RDONLY | O_CREAT | O_CLOEXEC; - if (exclusive) { - flags |= O_EXCL; - } - const int fd = TEMP_FAILURE_RETRY(openat(ns.fd(), ns.path(), flags, 0666)); - if (fd < 0) { - return false; - } - // File.create returns a File, so we shouldn't be giving the illusion that the - // call has created a file or that a file already exists if there is already - // an entity at the same path that is a directory or a link. - bool is_file = true; - struct stat st; - if (TEMP_FAILURE_RETRY(fstat(fd, &st)) == 0) { - if (S_ISDIR(st.st_mode)) { - errno = EISDIR; - is_file = false; - } else if (S_ISLNK(st.st_mode)) { - errno = ENOENT; - is_file = false; - } - } - FDUtils::SaveErrorAndClose(fd); - return is_file; -} - -// symlinkat is added to Android libc in android-21. -static int SymlinkAt(const char* oldpath, int newdirfd, const char* newpath) { - return syscall(__NR_symlinkat, oldpath, newdirfd, newpath); -} - -bool File::CreateLink(Namespace* namespc, - const char* name, - const char* target) { - NamespaceScope ns(namespc, name); - return NO_RETRY_EXPECTED(SymlinkAt(target, ns.fd(), ns.path())) == 0; -} - -bool File::CreatePipe(Namespace* namespc, File** readPipe, File** writePipe) { - int pipe_fds[2]; - int status = NO_RETRY_EXPECTED(pipe(pipe_fds)); - if (status != 0) { - return false; - } - *readPipe = OpenFD(pipe_fds[0]); - *writePipe = OpenFD(pipe_fds[1]); - return true; -} - -File::Type File::GetType(Namespace* namespc, - const char* name, - bool follow_links) { - NamespaceScope ns(namespc, name); - struct stat entry_info; - int stat_success; - if (follow_links) { - stat_success = - TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), &entry_info, 0)); - } else { - stat_success = TEMP_FAILURE_RETRY( - fstatat(ns.fd(), ns.path(), &entry_info, AT_SYMLINK_NOFOLLOW)); - } - if (stat_success == -1) { - return File::kDoesNotExist; - } - if (S_ISDIR(entry_info.st_mode)) { - return File::kIsDirectory; - } - if (S_ISREG(entry_info.st_mode)) { - return File::kIsFile; - } - if (S_ISLNK(entry_info.st_mode)) { - return File::kIsLink; - } - if (S_ISSOCK(entry_info.st_mode)) { - return File::kIsSock; - } - if (S_ISFIFO(entry_info.st_mode)) { - return File::kIsPipe; - } - return File::kDoesNotExist; -} - -static void SetErrno(File::Type type) { - switch (type) { - case File::kIsDirectory: - errno = EISDIR; - break; - case File::kDoesNotExist: - errno = ENOENT; - break; - default: - errno = EINVAL; - break; - } -} - -static bool CheckTypeAndSetErrno(Namespace* namespc, - const char* name, - File::Type expected, - bool follow_links) { - File::Type actual = File::GetType(namespc, name, follow_links); - if (actual == expected) { - return true; - } - SetErrno(actual); - return false; -} - -bool File::Delete(Namespace* namespc, const char* name) { - NamespaceScope ns(namespc, name); - File::Type type = File::GetType(namespc, name, true); - if (type == kIsFile || type == kIsSock || type == kIsPipe) { - return (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0); - } - SetErrno(type); - return false; -} - -bool File::DeleteLink(Namespace* namespc, const char* name) { - NamespaceScope ns(namespc, name); - return CheckTypeAndSetErrno(namespc, name, kIsLink, false) && - (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0); -} - -bool File::Rename(Namespace* namespc, - const char* old_path, - const char* new_path) { - File::Type type = File::GetType(namespc, old_path, true); - if (type == kIsFile || type == kIsSock || type == kIsPipe) { - NamespaceScope oldns(namespc, old_path); - NamespaceScope newns(namespc, new_path); - return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(), - newns.path())) == 0); - } - SetErrno(type); - return false; -} - -bool File::RenameLink(Namespace* namespc, - const char* old_path, - const char* new_path) { - NamespaceScope oldns(namespc, old_path); - NamespaceScope newns(namespc, new_path); - return CheckTypeAndSetErrno(namespc, old_path, kIsLink, false) && - (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(), - newns.path())) == 0); -} - -bool File::Copy(Namespace* namespc, - const char* old_path, - const char* new_path) { - File::Type type = File::GetType(namespc, old_path, true); - if (type != kIsFile && type != kIsSock && type != kIsPipe) { - SetErrno(type); - return false; - } - NamespaceScope oldns(namespc, old_path); - struct stat st; - if (TEMP_FAILURE_RETRY(fstatat(oldns.fd(), oldns.path(), &st, 0)) != 0) { - return false; - } - const int old_fd = TEMP_FAILURE_RETRY( - openat(oldns.fd(), oldns.path(), O_RDONLY | O_CLOEXEC)); - if (old_fd < 0) { - return false; - } - NamespaceScope newns(namespc, new_path); - const int new_fd = TEMP_FAILURE_RETRY( - openat(newns.fd(), newns.path(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, - st.st_mode)); - if (new_fd < 0) { - close(old_fd); - return false; - } - off_t offset = 0; - intptr_t result = 1; - while (result > 0) { - // Loop to ensure we copy everything, and not only up to 2GB. - result = NO_RETRY_EXPECTED(sendfile(new_fd, old_fd, &offset, kMaxUint32)); - } - // From sendfile man pages: - // Applications may wish to fall back to read(2)/write(2) in the case - // where sendfile() fails with EINVAL or ENOSYS. - if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) { - const intptr_t kBufferSize = 8 * KB; - uint8_t* buffer = reinterpret_cast(malloc(kBufferSize)); - while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) > - 0) { - int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); - if (wrote != result) { - result = -1; - break; - } - } - free(buffer); - } - int e = errno; - close(old_fd); - close(new_fd); - if (result < 0) { - VOID_NO_RETRY_EXPECTED(unlinkat(newns.fd(), newns.path(), 0)); - errno = e; - return false; - } - return true; -} - -static bool StatHelper(Namespace* namespc, const char* name, struct stat* st) { - NamespaceScope ns(namespc, name); - if (TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), st, 0)) != 0) { - return false; - } - // Signal an error if it's a directory. - if (S_ISDIR(st->st_mode)) { - errno = EISDIR; - return false; - } - // Otherwise assume the caller knows what it's doing. - return true; -} - -int64_t File::LengthFromPath(Namespace* namespc, const char* name) { - struct stat st; - if (!StatHelper(namespc, name, &st)) { - return -1; - } - return st.st_size; -} - -static void MillisecondsToTimespec(int64_t millis, struct timespec* t) { - ASSERT(t != nullptr); - t->tv_sec = millis / kMillisecondsPerSecond; - t->tv_nsec = (millis % kMillisecondsPerSecond) * 1000L; -} - -void File::Stat(Namespace* namespc, const char* name, int64_t* data) { - NamespaceScope ns(namespc, name); - struct stat st; - if (TEMP_FAILURE_RETRY(fstatat(ns.fd(), ns.path(), &st, 0)) == 0) { - if (S_ISREG(st.st_mode)) { - data[kType] = kIsFile; - } else if (S_ISDIR(st.st_mode)) { - data[kType] = kIsDirectory; - } else if (S_ISLNK(st.st_mode)) { - data[kType] = kIsLink; - } else if (S_ISSOCK(st.st_mode)) { - data[kType] = kIsSock; - } else if (S_ISFIFO(st.st_mode)) { - data[kType] = kIsPipe; - } else { - data[kType] = kDoesNotExist; - } - data[kCreatedTime] = static_cast(st.st_ctime) * 1000; - data[kModifiedTime] = static_cast(st.st_mtime) * 1000; - data[kAccessedTime] = static_cast(st.st_atime) * 1000; - data[kMode] = st.st_mode; - data[kSize] = st.st_size; - } else { - data[kType] = kDoesNotExist; - } -} - -time_t File::LastModified(Namespace* namespc, const char* name) { - struct stat st; - if (!StatHelper(namespc, name, &st)) { - return -1; - } - return st.st_mtime; -} - -time_t File::LastAccessed(Namespace* namespc, const char* name) { - struct stat st; - if (!StatHelper(namespc, name, &st)) { - return -1; - } - return st.st_atime; -} - -bool File::SetLastAccessed(Namespace* namespc, - const char* name, - int64_t millis) { - // First get the current times. - struct stat st; - if (!StatHelper(namespc, name, &st)) { - return false; - } - - // Set the new time: - NamespaceScope ns(namespc, name); - struct timespec times[2]; - MillisecondsToTimespec(millis, ×[0]); - MillisecondsToTimespec(static_cast(st.st_mtime) * 1000, ×[1]); - return utimensat(ns.fd(), ns.path(), times, 0) == 0; -} - -bool File::SetLastModified(Namespace* namespc, - const char* name, - int64_t millis) { - // First get the current times. - struct stat st; - if (!StatHelper(namespc, name, &st)) { - return false; - } - - // Set the new time: - NamespaceScope ns(namespc, name); - struct timespec times[2]; - MillisecondsToTimespec(static_cast(st.st_atime) * 1000, ×[0]); - MillisecondsToTimespec(millis, ×[1]); - return utimensat(ns.fd(), ns.path(), times, 0) == 0; -} - -// readlinkat is added to Android libc in android-21. -static int ReadLinkAt(int dirfd, - const char* pathname, - char* buf, - size_t bufsize) { - return syscall(__NR_readlinkat, dirfd, pathname, buf, bufsize); -} - -const char* File::LinkTarget(Namespace* namespc, - const char* name, - char* dest, - int dest_size) { - NamespaceScope ns(namespc, name); - struct stat link_stats; - const int status = TEMP_FAILURE_RETRY( - fstatat(ns.fd(), ns.path(), &link_stats, AT_SYMLINK_NOFOLLOW)); - if (status != 0) { - return nullptr; - } - if (!S_ISLNK(link_stats.st_mode)) { - errno = ENOENT; - return nullptr; - } - // Don't rely on the link_stats.st_size for the size of the link - // target. For some filesystems, e.g. procfs, this value is always - // 0. Also the link might have changed before the readlink call. - const int kBufferSize = PATH_MAX + 1; - char target[kBufferSize]; - const int target_size = - TEMP_FAILURE_RETRY(ReadLinkAt(ns.fd(), ns.path(), target, kBufferSize)); - if (target_size <= 0) { - return nullptr; - } - if (dest == nullptr) { - dest = DartUtils::ScopedCString(target_size + 1); - } else { - ASSERT(dest_size > 0); - if (dest_size <= target_size) { - return nullptr; - } - } - memmove(dest, target, target_size); - dest[target_size] = '\0'; - return dest; -} - -bool File::IsAbsolutePath(const char* pathname) { - return ((pathname != nullptr) && (pathname[0] == '/')); -} - -intptr_t File::ReadLinkInto(const char* pathname, - char* result, - size_t result_size) { - ASSERT(pathname != nullptr); - ASSERT(IsAbsolutePath(pathname)); - struct stat link_stats; - if (TEMP_FAILURE_RETRY(lstat(pathname, &link_stats)) != 0) { - return -1; - } - if (!S_ISLNK(link_stats.st_mode)) { - errno = ENOENT; - return -1; - } - size_t target_size = - TEMP_FAILURE_RETRY(readlink(pathname, result, result_size)); - if (target_size <= 0) { - return -1; - } - // readlink returns non-zero terminated strings. Append. - if (target_size < result_size) { - result[target_size] = '\0'; - target_size++; - } - return target_size; -} - -const char* File::ReadLink(const char* pathname) { - // Don't rely on the link_stats.st_size for the size of the link - // target. For some filesystems, e.g. procfs, this value is always - // 0. Also the link might have changed before the readlink call. - const int kBufferSize = PATH_MAX + 1; - char target[kBufferSize]; - size_t target_size = ReadLinkInto(pathname, target, kBufferSize); - if (target_size <= 0) { - return nullptr; - } - char* target_name = DartUtils::ScopedCString(target_size); - ASSERT(target_name != nullptr); - memmove(target_name, target, target_size); - return target_name; -} - -const char* File::GetCanonicalPath(Namespace* namespc, - const char* name, - char* dest, - int dest_size) { - if (name == nullptr) { - return nullptr; - } - if (!Namespace::IsDefault(namespc)) { - // TODO(zra): There is no realpathat(). Also chasing a symlink might result - // in a path to something outside of the namespace, so canonicalizing paths - // would have to be done carefully. For now, don't do anything. - return name; - } - char* abs_path; - if (dest == nullptr) { - dest = DartUtils::ScopedCString(PATH_MAX + 1); - } else { - ASSERT(dest_size >= PATH_MAX); - } - ASSERT(dest != nullptr); - do { - abs_path = realpath(name, dest); - } while ((abs_path == nullptr) && (errno == EINTR)); - ASSERT(abs_path == nullptr || IsAbsolutePath(abs_path)); - ASSERT(abs_path == nullptr || (abs_path == dest)); - return abs_path; -} - -const char* File::PathSeparator() { - return "/"; -} - -const char* File::StringEscapedPathSeparator() { - return "/"; -} - -File::StdioHandleType File::GetStdioHandleType(int fd) { - struct stat buf; - int result = fstat(fd, &buf); - if (result == -1) { - return kTypeError; - } - if (S_ISCHR(buf.st_mode)) { - return kTerminal; - } - if (S_ISFIFO(buf.st_mode)) { - return kPipe; - } - if (S_ISSOCK(buf.st_mode)) { - return kSocket; - } - if (S_ISREG(buf.st_mode)) { - return kFile; - } - return kOther; -} - -File::Identical File::AreIdentical(Namespace* namespc_1, - const char* file_1, - Namespace* namespc_2, - const char* file_2) { - struct stat file_1_info; - struct stat file_2_info; - int status; - { - NamespaceScope ns1(namespc_1, file_1); - status = TEMP_FAILURE_RETRY( - fstatat(ns1.fd(), ns1.path(), &file_1_info, AT_SYMLINK_NOFOLLOW)); - if (status == -1) { - return File::kError; - } - } - { - NamespaceScope ns2(namespc_2, file_2); - status = TEMP_FAILURE_RETRY( - fstatat(ns2.fd(), ns2.path(), &file_2_info, AT_SYMLINK_NOFOLLOW)); - if (status == -1) { - return File::kError; - } - } - return ((file_1_info.st_ino == file_2_info.st_ino) && - (file_1_info.st_dev == file_2_info.st_dev)) - ? File::kIdentical - : File::kDifferent; -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc index 08ac63f65d2..1c53c78bda2 100644 --- a/runtime/bin/file_linux.cc +++ b/runtime/bin/file_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/file.h" @@ -103,6 +103,7 @@ MappedMemory* File::Map(MapType type, } void* addr = mmap(hint, length, prot, flags, handle_->fd(), position); +#if defined(DART_HOST_OS_LINUX) // On WSL 1 trying to allocate memory close to the binary by supplying a hint // fails with ENOMEM for unclear reason. Some reports suggest that this might // be related to the alignment of the hint but aligning it by 64Kb does not @@ -112,6 +113,7 @@ MappedMemory* File::Map(MapType type, Utils::IsWindowsSubsystemForLinux()) { addr = mmap(nullptr, length, prot, flags, handle_->fd(), position); } +#endif if (addr == MAP_FAILED) { return nullptr; @@ -795,4 +797,4 @@ File::Identical File::AreIdentical(Namespace* namespc_1, } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/file_system_watcher_android.cc b/runtime/bin/file_system_watcher_android.cc deleted file mode 100644 index b2f58a61e6e..00000000000 --- a/runtime/bin/file_system_watcher_android.cc +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) 2013, 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_ANDROID) - -#include "bin/file_system_watcher.h" - -#include // NOLINT -#include // NOLINT - -#include "bin/fdutils.h" -#include "bin/file.h" -#include "bin/socket.h" -#include "platform/signal_blocker.h" - -namespace dart { -namespace bin { - -bool FileSystemWatcher::IsSupported() { - return true; -} - -intptr_t FileSystemWatcher::Init() { - int id = NO_RETRY_EXPECTED(inotify_init()); - if (id < 0 || !FDUtils::SetCloseOnExec(id)) { - return -1; - } - // Some systems don't support setting this as non-blocking. Since watching - // internals are kept away from the user, we know it's possible to continue, - // even if setting non-blocking fails. - FDUtils::SetNonBlocking(id); - return id; -} - -void FileSystemWatcher::Close(intptr_t id) { - USE(id); -} - -intptr_t FileSystemWatcher::WatchPath(intptr_t id, - Namespace* namespc, - const char* path, - int events, - bool recursive) { - int list_events = IN_DELETE_SELF | IN_MOVE_SELF; - if ((events & kCreate) != 0) { - list_events |= IN_CREATE; - } - if ((events & kModifyContent) != 0) { - list_events |= IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY; - } - if ((events & kDelete) != 0) { - list_events |= IN_DELETE; - } - if ((events & kMove) != 0) { - list_events |= IN_MOVE; - } - const char* resolved_path = File::GetCanonicalPath(namespc, path); - path = resolved_path != nullptr ? resolved_path : path; - int path_id = - NO_RETRY_EXPECTED(inotify_add_watch(id, resolved_path, list_events)); - if (path_id < 0) { - return -1; - } - return path_id; -} - -void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) { - VOID_NO_RETRY_EXPECTED(inotify_rm_watch(id, path_id)); -} - -intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) { - USE(path_id); - return id; -} - -static int InotifyEventToMask(struct inotify_event* e) { - int mask = 0; - if ((e->mask & IN_CLOSE_WRITE) != 0 || (e->mask & IN_MODIFY) != 0) { - mask |= FileSystemWatcher::kModifyContent; - } - if ((e->mask & IN_ATTRIB) != 0) { - mask |= FileSystemWatcher::kModifyAttribute; - } - if ((e->mask & IN_CREATE) != 0) { - mask |= FileSystemWatcher::kCreate; - } - if ((e->mask & IN_MOVE) != 0) { - mask |= FileSystemWatcher::kMove; - } - if ((e->mask & IN_DELETE) != 0) { - mask |= FileSystemWatcher::kDelete; - } - if ((e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) != 0) { - mask |= FileSystemWatcher::kDeleteSelf; - } - if ((e->mask & IN_ISDIR) != 0) { - mask |= FileSystemWatcher::kIsDir; - } - return mask; -} - -Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) { - USE(path_id); - const intptr_t kEventSize = sizeof(struct inotify_event); - const intptr_t kBufferSize = kEventSize + NAME_MAX + 1; - uint8_t buffer[kBufferSize]; - intptr_t bytes = TEMP_FAILURE_RETRY(read(id, buffer, kBufferSize)); - if (bytes < 0) { - ASSERT(EAGAIN == EWOULDBLOCK); - if ((bytes == -1) && (errno == EWOULDBLOCK)) { - // see also SocketBase::Read - bytes = 0; - } else { - return DartUtils::NewDartOSError(); - } - } - const intptr_t kMaxCount = bytes / kEventSize; - Dart_Handle events = Dart_NewList(kMaxCount); - intptr_t offset = 0; - intptr_t i = 0; - while (offset < bytes) { - struct inotify_event* e = - reinterpret_cast(buffer + offset); - if ((e->mask & IN_IGNORED) == 0) { - Dart_Handle event = Dart_NewList(5); - int mask = InotifyEventToMask(e); - Dart_ListSetAt(event, 0, Dart_NewInteger(mask)); - Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie)); - if (e->len > 0) { - Dart_Handle name = Dart_NewStringFromUTF8( - reinterpret_cast(e->name), strlen(e->name)); - if (Dart_IsError(name)) { - return name; - } - Dart_ListSetAt(event, 2, name); - } else { - Dart_ListSetAt(event, 2, Dart_Null()); - } - Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO)); - Dart_ListSetAt(event, 4, Dart_NewInteger(e->wd)); - Dart_ListSetAt(events, i, event); - i++; - } - offset += kEventSize + e->len; - } - ASSERT(offset == bytes); - return events; -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/file_system_watcher_linux.cc b/runtime/bin/file_system_watcher_linux.cc index e7a51da89d9..9b78e3fae5d 100644 --- a/runtime/bin/file_system_watcher_linux.cc +++ b/runtime/bin/file_system_watcher_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/file_system_watcher.h" @@ -146,4 +146,4 @@ Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/ifaddrs-android.cc b/runtime/bin/ifaddrs.cc similarity index 98% rename from runtime/bin/ifaddrs-android.cc rename to runtime/bin/ifaddrs.cc index c56f31de2af..355454dcaf4 100644 --- a/runtime/bin/ifaddrs-android.cc +++ b/runtime/bin/ifaddrs.cc @@ -1,10 +1,10 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2024, 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. #if defined(ANDROID) && __ANDROID_API__ < 24 -#include "bin/ifaddrs-android.h" +#include "bin/ifaddrs.h" #include #include diff --git a/runtime/bin/ifaddrs-android.h b/runtime/bin/ifaddrs.h similarity index 63% rename from runtime/bin/ifaddrs-android.h rename to runtime/bin/ifaddrs.h index ec0ecd26a93..2a3b7033a75 100644 --- a/runtime/bin/ifaddrs-android.h +++ b/runtime/bin/ifaddrs.h @@ -1,9 +1,13 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2024, 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. -#ifndef RUNTIME_BIN_IFADDRS_ANDROID_H_ -#define RUNTIME_BIN_IFADDRS_ANDROID_H_ +#ifndef RUNTIME_BIN_IFADDRS_H_ +#define RUNTIME_BIN_IFADDRS_H_ + +// On Android getifaddrs API which is only supported directly by +// Bionic starting at API level 24 so we provide our own implementation +// which is API compatible. Otherwise we just include system ifaddrs.h #if defined(ANDROID) && __ANDROID_API__ < 24 #include @@ -30,5 +34,10 @@ int getifaddrs(struct ifaddrs** __list_ptr); } // namespace bin } // namespace dart +#else + +#include + #endif // defined(ANDROID) && __ANDROID_API__ < 24 -#endif // RUNTIME_BIN_IFADDRS_ANDROID_H_ + +#endif // RUNTIME_BIN_IFADDRS_H_ diff --git a/runtime/bin/io_impl_sources.gni b/runtime/bin/io_impl_sources.gni index f2c1be724ef..d3ace672e9b 100644 --- a/runtime/bin/io_impl_sources.gni +++ b/runtime/bin/io_impl_sources.gni @@ -10,8 +10,6 @@ io_impl_sources = [ "console_win.cc", "eventhandler.cc", "eventhandler.h", - "eventhandler_android.cc", - "eventhandler_android.h", "eventhandler_fuchsia.cc", "eventhandler_fuchsia.h", "eventhandler_linux.cc", @@ -22,22 +20,20 @@ io_impl_sources = [ "eventhandler_win.h", "file_system_watcher.cc", "file_system_watcher.h", - "file_system_watcher_android.cc", "file_system_watcher_fuchsia.cc", "file_system_watcher_linux.cc", "file_system_watcher_macos.cc", "file_system_watcher_win.cc", "filter.cc", "filter.h", - "ifaddrs-android.cc", - "ifaddrs-android.h", + "ifaddrs.cc", + "ifaddrs.h", "io_service.cc", "io_service.h", "io_service_no_ssl.cc", "io_service_no_ssl.h", "namespace.cc", "namespace.h", - "namespace_android.cc", "namespace_fuchsia.cc", "namespace_fuchsia.h", "namespace_linux.cc", @@ -45,7 +41,6 @@ io_impl_sources = [ "namespace_win.cc", "platform.cc", "platform.h", - "platform_android.cc", "platform_fuchsia.cc", "platform_linux.cc", "platform_macos.cc", @@ -53,7 +48,6 @@ io_impl_sources = [ "platform_win.cc", "process.cc", "process.h", - "process_android.cc", "process_fuchsia.cc", "process_linux.cc", "process_macos.cc", @@ -67,18 +61,14 @@ io_impl_sources = [ "secure_socket_utils.h", "security_context.cc", "security_context.h", - "security_context_android.cc", "security_context_fuchsia.cc", "security_context_linux.cc", "security_context_macos.cc", "security_context_win.cc", "socket.cc", "socket.h", - "socket_android.cc", "socket_base.cc", "socket_base.h", - "socket_base_android.cc", - "socket_base_android.h", "socket_base_fuchsia.cc", "socket_base_fuchsia.h", "socket_base_linux.cc", @@ -94,14 +84,12 @@ io_impl_sources = [ "socket_win.cc", "stdio.cc", "stdio.h", - "stdio_android.cc", "stdio_fuchsia.cc", "stdio_linux.cc", "stdio_macos.cc", "stdio_win.cc", "sync_socket.cc", "sync_socket.h", - "sync_socket_android.cc", "sync_socket_fuchsia.cc", "sync_socket_linux.cc", "sync_socket_macos.cc", diff --git a/runtime/bin/namespace_android.cc b/runtime/bin/namespace_android.cc deleted file mode 100644 index b44245f0979..00000000000 --- a/runtime/bin/namespace_android.cc +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2017, 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_ANDROID) - -#include "bin/namespace.h" - -#include -#include - -#include "bin/file.h" -#include "platform/signal_blocker.h" -#include "platform/text_buffer.h" - -namespace dart { -namespace bin { - -class NamespaceImpl { - public: - explicit NamespaceImpl(intptr_t rootfd) : rootfd_(rootfd), cwd_(strdup("/")) { - ASSERT(rootfd_ > 0); - cwdfd_ = dup(rootfd_); - ASSERT(cwdfd_ > 0); - } - - explicit NamespaceImpl(const char* path) - : rootfd_(TEMP_FAILURE_RETRY(open(path, O_DIRECTORY))), - cwd_(strdup("/")) { - ASSERT(rootfd_ > 0); - cwdfd_ = dup(rootfd_); - ASSERT(cwdfd_ > 0); - } - - ~NamespaceImpl() { - NO_RETRY_EXPECTED(close(rootfd_)); - free(cwd_); - NO_RETRY_EXPECTED(close(cwdfd_)); - } - - intptr_t rootfd() const { return rootfd_; } - char* cwd() const { return cwd_; } - intptr_t cwdfd() const { return cwdfd_; } - - bool SetCwd(Namespace* namespc, const char* new_path) { - NamespaceScope ns(namespc, new_path); - const intptr_t new_cwdfd = - TEMP_FAILURE_RETRY(openat(ns.fd(), ns.path(), O_DIRECTORY)); - if (new_cwdfd < 0) { - return false; - } - - TextBuffer tbuf(PATH_MAX); - if (!File::IsAbsolutePath(new_path)) { - tbuf.AddString(cwd_); - } - tbuf.AddString(File::PathSeparator()); - tbuf.AddString(ns.path()); - - // Normalize it. - char result[PATH_MAX]; - const intptr_t result_len = - File::CleanUnixPath(tbuf.buffer(), result, PATH_MAX); - if (result_len < 0) { - errno = ENAMETOOLONG; - return false; - } - - free(cwd_); - cwd_ = strdup(result); - close(cwdfd_); - cwdfd_ = new_cwdfd; - return true; - } - - private: - intptr_t rootfd_; // dirfd for the namespace root. - char* cwd_; // cwd relative to the namespace. - intptr_t cwdfd_; // dirfd for the cwd. - - DISALLOW_COPY_AND_ASSIGN(NamespaceImpl); -}; - -Namespace* Namespace::Create(intptr_t namespc) { - NamespaceImpl* namespc_impl = nullptr; - if (namespc != kNone) { - namespc_impl = new NamespaceImpl(namespc); - } - return new Namespace(namespc_impl); -} - -Namespace* Namespace::Create(const char* path) { - return new Namespace(new NamespaceImpl(path)); -} - -Namespace::~Namespace() { - delete namespc_; -} - -intptr_t Namespace::Default() { - return kNone; -} - -const char* Namespace::GetCurrent(Namespace* namespc) { - if (Namespace::IsDefault(namespc)) { - char buffer[PATH_MAX]; - if (getcwd(buffer, PATH_MAX) == nullptr) { - return nullptr; - } - return DartUtils::ScopedCopyCString(buffer); - } - const char* cwd = namespc->namespc()->cwd(); - return cwd; -} - -bool Namespace::SetCurrent(Namespace* namespc, const char* path) { - if (Namespace::IsDefault(namespc)) { - return (NO_RETRY_EXPECTED(chdir(path)) == 0); - } - return namespc->namespc()->SetCwd(namespc, path); -} - -void Namespace::ResolvePath(Namespace* namespc, - const char* path, - intptr_t* dirfd, - const char** resolved_path) { - ASSERT(dirfd != nullptr); - ASSERT(resolved_path != nullptr); - if (Namespace::IsDefault(namespc)) { - *dirfd = AT_FDCWD; - *resolved_path = path; - return; - } - if (File::IsAbsolutePath(path)) { - *dirfd = namespc->namespc()->rootfd(); - if (strcmp(path, File::PathSeparator()) == 0) { - // Change "/" to ".". - *resolved_path = "."; - } else { - // Otherwise strip off the leading "/". - *resolved_path = &path[1]; - } - } else { - *dirfd = namespc->namespc()->cwdfd(); - *resolved_path = path; - } -} - -NamespaceScope::NamespaceScope(Namespace* namespc, const char* path) { - Namespace::ResolvePath(namespc, path, &fd_, &path_); -} - -NamespaceScope::~NamespaceScope() {} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/namespace_linux.cc b/runtime/bin/namespace_linux.cc index db94d561dbe..c48ec219d01 100644 --- a/runtime/bin/namespace_linux.cc +++ b/runtime/bin/namespace_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/namespace.h" @@ -156,4 +156,4 @@ NamespaceScope::~NamespaceScope() {} } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/platform_android.cc b/runtime/bin/platform_android.cc deleted file mode 100644 index b682e3d60a5..00000000000 --- a/runtime/bin/platform_android.cc +++ /dev/null @@ -1,208 +0,0 @@ -// 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_ANDROID) - -#include "bin/platform.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#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() { - 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; - } - ASSERT(os_version_length <= PROP_VALUE_MAX); - char* result = reinterpret_cast( - Dart_ScopeAllocate((os_version_length + 1) * sizeof(result))); - strncpy(result, os_version, (os_version_length + 1)); - return result; -} - -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(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(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(value), static_cast(value)}; - setrlimit(RLIMIT_CORE, &limit); -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/platform_linux.cc b/runtime/bin/platform_linux.cc index fe9cda64a50..4fed598047c 100644 --- a/runtime/bin/platform_linux.cc +++ b/runtime/bin/platform_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/platform.h" @@ -12,6 +12,9 @@ #include #include #include +#if defined(DART_HOST_OS_ANDROID) +#include +#endif #include #include @@ -118,25 +121,24 @@ int Platform::NumberOfProcessors() { } 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; } - const char* kFormat = "%s %s %s"; - int len = - snprintf(nullptr, 0, kFormat, info.sysname, info.release, info.version); - if (len <= 0) { - return nullptr; - } - char* result = DartUtils::ScopedCString(len + 1); - ASSERT(result != nullptr); - len = snprintf(result, len + 1, kFormat, info.sysname, info.release, - info.version); - if (len <= 0) { - return nullptr; - } - return result; + return DartUtils::ScopedCStringFormatted("%s %s %s", info.sysname, + info.release, info.version); +#endif } const char* Platform::LibraryPrefix() { @@ -212,4 +214,4 @@ void Platform::SetCoreDumpResourceLimit(int value) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc index 40253c49efc..febd96ccb92 100644 --- a/runtime/bin/platform_win.cc +++ b/runtime/bin/platform_win.cc @@ -164,18 +164,7 @@ static const char* VersionNumber() { if (!GetCurrentVersionDWord(L"CurrentMinorVersionNumber", &minor)) { return nullptr; } - const char* kFormat = "%d.%d"; - int len = snprintf(nullptr, 0, kFormat, major, minor); - if (len < 0) { - return nullptr; - } - char* result = DartUtils::ScopedCString(len + 1); - ASSERT(result != nullptr); - len = snprintf(result, len + 1, kFormat, major, minor); - if (len < 0) { - return nullptr; - } - return result; + return DartUtils::ScopedCStringFormatted("%d.%d", major, minor); } const char* Platform::OperatingSystemVersion() { diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc deleted file mode 100644 index b560b852aef..00000000000 --- a/runtime/bin/process_android.cc +++ /dev/null @@ -1,1169 +0,0 @@ -// 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_ANDROID) - -#include "bin/process.h" - -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#include "bin/dartutils.h" -#include "bin/directory.h" -#include "bin/fdutils.h" -#include "bin/file.h" -#include "bin/lockers.h" -#include "bin/namespace.h" -#include "bin/reference_counting.h" -#include "bin/thread.h" -#include "platform/syslog.h" - -#include "platform/signal_blocker.h" -#include "platform/utils.h" - -extern char** environ; - -namespace dart { -namespace bin { - -int Process::global_exit_code_ = 0; -Mutex* Process::global_exit_code_mutex_ = nullptr; -Process::ExitHook Process::exit_hook_ = nullptr; - -// ProcessInfo is used to map a process id to the file descriptor for -// the pipe used to communicate the exit code of the process to Dart. -// ProcessInfo objects are kept in the static singly-linked -// ProcessInfoList. -class ProcessInfo { - public: - ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) {} - ~ProcessInfo() { - int closed = close(fd_); - if (closed != 0) { - FATAL("Failed to close process exit code pipe"); - } - } - pid_t pid() { return pid_; } - intptr_t fd() { return fd_; } - ProcessInfo* next() { return next_; } - void set_next(ProcessInfo* info) { next_ = info; } - - private: - pid_t pid_; - intptr_t fd_; - ProcessInfo* next_; - - DISALLOW_COPY_AND_ASSIGN(ProcessInfo); -}; - -// Singly-linked list of ProcessInfo objects for all active processes -// started from Dart. -class ProcessInfoList { - public: - static void Init(); - static void Cleanup(); - - static void AddProcess(pid_t pid, intptr_t fd) { - MutexLocker locker(mutex_); - ProcessInfo* info = new ProcessInfo(pid, fd); - info->set_next(active_processes_); - active_processes_ = info; - } - - static intptr_t LookupProcessExitFd(pid_t pid) { - MutexLocker locker(mutex_); - ProcessInfo* current = active_processes_; - while (current != nullptr) { - if (current->pid() == pid) { - return current->fd(); - } - current = current->next(); - } - return 0; - } - - static void RemoveProcess(pid_t pid) { - MutexLocker locker(mutex_); - ProcessInfo* prev = nullptr; - ProcessInfo* current = active_processes_; - while (current != nullptr) { - if (current->pid() == pid) { - if (prev == nullptr) { - active_processes_ = current->next(); - } else { - prev->set_next(current->next()); - } - delete current; - return; - } - prev = current; - current = current->next(); - } - } - - private: - // Linked list of ProcessInfo objects for all active processes - // started from Dart code. - static ProcessInfo* active_processes_; - // Mutex protecting all accesses to the linked list of active - // processes. - static Mutex* mutex_; - - DISALLOW_ALLOCATION(); - DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessInfoList); -}; - -ProcessInfo* ProcessInfoList::active_processes_ = nullptr; -Mutex* ProcessInfoList::mutex_ = nullptr; - -// The exit code handler sets up a separate thread which waits for child -// processes to terminate. That separate thread can then get the exit code from -// processes that have exited and communicate it to Dart through the -// event loop. -class ExitCodeHandler { - public: - static void Init(); - static void Cleanup(); - - // Notify the ExitCodeHandler that another process exists. - static void ProcessStarted() { - // Multiple isolates could be starting processes at the same - // time. Make sure that only one ExitCodeHandler thread exists. - MonitorLocker locker(monitor_); - process_count_++; - - monitor_->Notify(); - - if (running_) { - return; - } - - // Start thread that handles process exits when wait returns. - int result = - Thread::Start("dart:io Process.start", ExitCodeHandlerEntry, 0); - if (result != 0) { - FATAL("Failed to start exit code handler worker thread %d", result); - } - - running_ = true; - } - - static void TerminateExitCodeThread() { - MonitorLocker locker(monitor_); - - if (!running_) { - return; - } - - // Set terminate_done_ to false, so we can use it as a guard for our - // monitor. - running_ = false; - - // Wake up the [ExitCodeHandler] thread which is blocked on `wait()` (see - // [ExitCodeHandlerEntry]). - if (TEMP_FAILURE_RETRY(fork()) == 0) { - // We avoid running through registered atexit() handlers because that is - // unnecessary work. - _exit(0); - } - - monitor_->Notify(); - - while (!terminate_done_) { - monitor_->Wait(Monitor::kNoTimeout); - } - } - - private: - // Entry point for the separate exit code handler thread started by - // the ExitCodeHandler. - static void ExitCodeHandlerEntry(uword param) { - pid_t pid = 0; - int status = 0; - while (true) { - { - MonitorLocker locker(monitor_); - while (running_ && (process_count_ == 0)) { - monitor_->Wait(Monitor::kNoTimeout); - } - if (!running_) { - terminate_done_ = true; - monitor_->Notify(); - return; - } - } - - if ((pid = TEMP_FAILURE_RETRY(wait(&status))) > 0) { - int exit_code = 0; - int negative = 0; - if (WIFEXITED(status)) { - exit_code = WEXITSTATUS(status); - } - if (WIFSIGNALED(status)) { - exit_code = WTERMSIG(status); - negative = 1; - } - intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid); - if (exit_code_fd != 0) { - int message[2] = {exit_code, negative}; - ssize_t result = - FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message)); - // If the process has been closed, the read end of the exit - // pipe has been closed. It is therefore not a problem that - // write fails with a broken pipe error. Other errors should - // not happen. - if ((result != -1) && (result != sizeof(message))) { - FATAL("Failed to write entire process exit message"); - } else if ((result == -1) && (errno != EPIPE)) { - FATAL("Failed to write exit code: %d", errno); - } - ProcessInfoList::RemoveProcess(pid); - { - MonitorLocker locker(monitor_); - process_count_--; - } - } - } else if (pid < 0) { - FATAL("Wait for process exit failed: %d", errno); - } - } - } - - static bool terminate_done_; - static int process_count_; - static bool running_; - static Monitor* monitor_; - - DISALLOW_ALLOCATION(); - DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler); -}; - -bool ExitCodeHandler::running_ = false; -int ExitCodeHandler::process_count_ = 0; -bool ExitCodeHandler::terminate_done_ = false; -Monitor* ExitCodeHandler::monitor_ = nullptr; - -class ProcessStarter { - public: - ProcessStarter(Namespace* namespc, - const char* path, - char* arguments[], - intptr_t arguments_length, - const char* working_directory, - char* environment[], - intptr_t environment_length, - ProcessStartMode mode, - intptr_t* in, - intptr_t* out, - intptr_t* err, - intptr_t* id, - intptr_t* exit_event, - char** os_error_message) - : namespc_(namespc), - path_(path), - working_directory_(working_directory), - mode_(mode), - in_(in), - out_(out), - err_(err), - id_(id), - exit_event_(exit_event), - os_error_message_(os_error_message) { - read_in_[0] = -1; - read_in_[1] = -1; - read_err_[0] = -1; - read_err_[1] = -1; - write_out_[0] = -1; - write_out_[1] = -1; - exec_control_[0] = -1; - exec_control_[1] = -1; - - program_arguments_ = reinterpret_cast(Dart_ScopeAllocate( - (arguments_length + 2) * sizeof(*program_arguments_))); - program_arguments_[0] = const_cast(path_); - for (int i = 0; i < arguments_length; i++) { - program_arguments_[i + 1] = arguments[i]; - } - program_arguments_[arguments_length + 1] = nullptr; - - program_environment_ = nullptr; - if (environment != nullptr) { - program_environment_ = reinterpret_cast(Dart_ScopeAllocate( - (environment_length + 1) * sizeof(*program_environment_))); - for (int i = 0; i < environment_length; i++) { - program_environment_[i] = environment[i]; - } - program_environment_[environment_length] = nullptr; - } - } - - int Start() { - // Create pipes required. - int err = CreatePipes(); - if (err != 0) { - return err; - } - - // Fork to create the new process. - pid_t pid = TEMP_FAILURE_RETRY(fork()); - if (pid < 0) { - // Failed to fork. - return CleanupAndReturnError(); - } else if (pid == 0) { - // This runs in the new process. - NewProcess(); - } - - // This runs in the original process. - - // If the child process is not started in detached mode, be sure to - // listen for exit-codes, now that we have a non detached child process - // and also Register this child process. - if (Process::ModeIsAttached(mode_)) { - ExitCodeHandler::ProcessStarted(); - err = RegisterProcess(pid); - if (err != 0) { - return err; - } - } - - // Notify child process to start. This is done to delay the call to exec - // until the process is registered above, and we are ready to receive the - // exit code. - char msg = '1'; - int bytes_written = - FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg)); - if (bytes_written != sizeof(msg)) { - return CleanupAndReturnError(); - } - - // Read the result of executing the child process. - close(exec_control_[1]); - exec_control_[1] = -1; - if (Process::ModeIsAttached(mode_)) { - err = ReadExecResult(); - } else { - err = ReadDetachedExecResult(&pid); - } - close(exec_control_[0]); - exec_control_[0] = -1; - - // Return error code if any failures. - if (err != 0) { - if (Process::ModeIsAttached(mode_)) { - // Since exec() failed, we're not interested in the exit code. - // We close the reading side of the exit code pipe here. - // GetProcessExitCodes will get a broken pipe error when it - // tries to write to the writing side of the pipe and it will - // ignore the error. - close(*exit_event_); - *exit_event_ = -1; - } - CloseAllPipes(); - return err; - } - - if (Process::ModeHasStdio(mode_)) { - // Connect stdio, stdout and stderr. - FDUtils::SetNonBlocking(read_in_[0]); - *in_ = read_in_[0]; - close(read_in_[1]); - FDUtils::SetNonBlocking(write_out_[1]); - *out_ = write_out_[1]; - close(write_out_[0]); - FDUtils::SetNonBlocking(read_err_[0]); - *err_ = read_err_[0]; - close(read_err_[1]); - } else { - // Close all fds. - close(read_in_[0]); - close(read_in_[1]); - ASSERT(write_out_[0] == -1); - ASSERT(write_out_[1] == -1); - ASSERT(read_err_[0] == -1); - ASSERT(read_err_[1] == -1); - } - ASSERT(exec_control_[0] == -1); - ASSERT(exec_control_[1] == -1); - - *id_ = pid; - return 0; - } - - private: - int CreatePipes() { - int result; - result = TEMP_FAILURE_RETRY(pipe2(exec_control_, O_CLOEXEC)); - if (result < 0) { - return CleanupAndReturnError(); - } - - // For a detached process the pipe to connect stdout is still used for - // signaling when to do the first fork. - result = TEMP_FAILURE_RETRY(pipe2(read_in_, O_CLOEXEC)); - if (result < 0) { - return CleanupAndReturnError(); - } - - // For detached processes the pipe to connect stderr and stdin are not used. - if (Process::ModeHasStdio(mode_)) { - result = TEMP_FAILURE_RETRY(pipe2(read_err_, O_CLOEXEC)); - if (result < 0) { - return CleanupAndReturnError(); - } - - result = TEMP_FAILURE_RETRY(pipe2(write_out_, O_CLOEXEC)); - if (result < 0) { - return CleanupAndReturnError(); - } - } - - return 0; - } - - void NewProcess() { - // Wait for parent process before setting up the child process. - char msg; - int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); - if (bytes_read != sizeof(msg)) { - perror("Failed receiving notification message"); - _exit(1); - } - if (Process::ModeIsAttached(mode_)) { - ExecProcess(); - } else { - ExecDetachedProcess(); - } - } - - // Tries to find path_ relative to the current namespace unless it should be - // searched in the PATH. - // The path that should be passed to exec is returned in realpath. - // Returns true on success, and false if there was an error that should - // be reported to the parent. - bool FindPathInNamespace(char* realpath, intptr_t realpath_size) { - // Perform a PATH search if there's no slash in the path. - if (Namespace::IsDefault(namespc_) || strchr(path_, '/') == nullptr) { - // TODO(zra): If there is a non-default namespace, the entries in PATH - // should be treated as relative to the namespace. - strncpy(realpath, path_, realpath_size); - realpath[realpath_size - 1] = '\0'; - return true; - } - NamespaceScope ns(namespc_, path_); - const int fd = - TEMP_FAILURE_RETRY(openat(ns.fd(), ns.path(), O_RDONLY | O_CLOEXEC)); - if (fd == -1) { - return false; - } - char procpath[PATH_MAX]; - snprintf(procpath, PATH_MAX, "/proc/self/fd/%d", fd); - const intptr_t length = - TEMP_FAILURE_RETRY(readlink(procpath, realpath, realpath_size)); - if (length < 0) { - FDUtils::SaveErrorAndClose(fd); - return false; - } - realpath[length] = '\0'; - FDUtils::SaveErrorAndClose(fd); - return true; - } - - void ExecProcess() { - if (mode_ == kNormal) { - if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { - ReportChildError(); - } - - if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { - ReportChildError(); - } - - if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { - ReportChildError(); - } - } else { - ASSERT(mode_ == kInheritStdio); - } - - if (working_directory_ != nullptr && - !Directory::SetCurrent(namespc_, working_directory_)) { - ReportChildError(); - } - - if (program_environment_ != nullptr) { - environ = program_environment_; - } - - char realpath[PATH_MAX]; - if (!FindPathInNamespace(realpath, PATH_MAX)) { - ReportChildError(); - } - // TODO(dart:io) Test for the existence of execveat, and use it instead. - execvp(realpath, const_cast(program_arguments_)); - ReportChildError(); - } - - void ExecDetachedProcess() { - if (mode_ == kDetached) { - ASSERT(write_out_[0] == -1); - ASSERT(write_out_[1] == -1); - ASSERT(read_err_[0] == -1); - ASSERT(read_err_[1] == -1); - // For a detached process the pipe to connect stdout is only used for - // signaling when to do the first fork. - close(read_in_[0]); - read_in_[0] = -1; - close(read_in_[1]); - read_in_[1] = -1; - } else { - // Don't close any fds if keeping stdio open to the detached process. - ASSERT(mode_ == kDetachedWithStdio); - } - // Fork once more to start a new session. - pid_t pid = TEMP_FAILURE_RETRY(fork()); - if (pid < 0) { - ReportChildError(); - } else if (pid == 0) { - // Start a new session. - if (TEMP_FAILURE_RETRY(setsid()) == -1) { - ReportChildError(); - } else { - // Do a final fork to not be the session leader. - pid = TEMP_FAILURE_RETRY(fork()); - if (pid < 0) { - ReportChildError(); - } else if (pid == 0) { - if (mode_ == kDetached) { - SetupDetached(); - } else { - SetupDetachedWithStdio(); - } - - if ((working_directory_ != nullptr) && - !Directory::SetCurrent(namespc_, working_directory_)) { - ReportChildError(); - } - - if (program_environment_ != nullptr) { - environ = program_environment_; - } - - // Report the final PID and do the exec. - ReportPid(getpid()); // getpid cannot fail. - char realpath[PATH_MAX]; - if (!FindPathInNamespace(realpath, PATH_MAX)) { - ReportChildError(); - } - // TODO(dart:io) Test for the existence of execveat, and use it - // instead. - execvp(realpath, const_cast(program_arguments_)); - ReportChildError(); - } else { - // Exit the intermediate process. Avoid calling any atexit callbacks - // to avoid potential issues (e.g. deadlocks). - _exit(0); - } - } - } else { - // Exit the intermediate process. Avoid calling any atexit callbacks - // to avoid potential issues (e.g. deadlocks). - _exit(0); - } - } - - int RegisterProcess(pid_t pid) { - int result; - int event_fds[2]; - result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC)); - if (result < 0) { - return CleanupAndReturnError(); - } - - ProcessInfoList::AddProcess(pid, event_fds[1]); - *exit_event_ = event_fds[0]; - FDUtils::SetNonBlocking(event_fds[0]); - return 0; - } - - int ReadExecResult() { - int child_errno; - int bytes_read = -1; - // Read exec result from child. If no data is returned the exec was - // successful and the exec call closed the pipe. Otherwise the errno - // is written to the pipe. - bytes_read = FDUtils::ReadFromBlocking(exec_control_[0], &child_errno, - sizeof(child_errno)); - if (bytes_read == sizeof(child_errno)) { - ReadChildError(); - return child_errno; - } else if (bytes_read == -1) { - return errno; - } - return 0; - } - - int ReadDetachedExecResult(pid_t* pid) { - int child_errno; - int bytes_read = -1; - // Read exec result from child. If only pid data is returned the exec was - // successful and the exec call closed the pipe. Otherwise the errno - // is written to the pipe as well. - int result[2]; - bytes_read = - FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result)); - if (bytes_read == sizeof(int)) { - *pid = result[0]; - } else if (bytes_read == 2 * sizeof(int)) { - *pid = result[0]; - child_errno = result[1]; - ReadChildError(); - return child_errno; - } else if (bytes_read == -1) { - return errno; - } - return 0; - } - - void SetupDetached() { - ASSERT(mode_ == kDetached); - - // Close all open file descriptors except for exec_control_[1]. - int max_fds = sysconf(_SC_OPEN_MAX); - if (max_fds == -1) { - max_fds = _POSIX_OPEN_MAX; - } - for (int fd = 0; fd < max_fds; fd++) { - if (fd != exec_control_[1]) { - close(fd); - } - } - - // Re-open stdin, stdout and stderr and connect them to /dev/null. - // The loop above should already have closed all of them, so - // creating new file descriptors should start at STDIN_FILENO. - int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); - if (fd != STDIN_FILENO) { - ReportChildError(); - } - if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) != - STDOUT_FILENO) { - ReportChildError(); - } - if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) != - STDERR_FILENO) { - ReportChildError(); - } - } - - void SetupDetachedWithStdio() { - // Close all open file descriptors except for - // exec_control_[1], write_out_[0], read_in_[1] and - // read_err_[1]. - int max_fds = sysconf(_SC_OPEN_MAX); - if (max_fds == -1) { - max_fds = _POSIX_OPEN_MAX; - } - for (int fd = 0; fd < max_fds; fd++) { - if ((fd != exec_control_[1]) && (fd != write_out_[0]) && - (fd != read_in_[1]) && (fd != read_err_[1])) { - close(fd); - } - } - - if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { - ReportChildError(); - } - close(write_out_[0]); - - if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { - ReportChildError(); - } - close(read_in_[1]); - - if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { - ReportChildError(); - } - close(read_err_[1]); - } - - int CleanupAndReturnError() { - int actual_errno = errno; - // If CleanupAndReturnError is called without an actual errno make - // sure to return an error anyway. - if (actual_errno == 0) { - actual_errno = EPERM; - } - SetChildOsErrorMessage(); - CloseAllPipes(); - return actual_errno; - } - - void SetChildOsErrorMessage() { - const int kBufferSize = 1024; - char* error_message = DartUtils::ScopedCString(kBufferSize); - Utils::StrError(errno, error_message, kBufferSize); - *os_error_message_ = error_message; - } - - void ReportChildError() { - // In the case of failure in the child process write the errno and - // the OS error message to the exec control pipe and exit. - int child_errno = errno; - const int kBufferSize = 1024; - char error_buf[kBufferSize]; - char* os_error_message = Utils::StrError(errno, error_buf, kBufferSize); - int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno, - sizeof(child_errno)); - if (bytes_written == sizeof(child_errno)) { - FDUtils::WriteToBlocking(exec_control_[1], os_error_message, - strlen(os_error_message) + 1); - } - close(exec_control_[1]); - - // We avoid running through registered atexit() handlers because that is - // unnecessary work. - _exit(1); - } - - void ReportPid(int pid) { - // In the case of starting a detached process the actual pid of that process - // is communicated using the exec control pipe. - int bytes_written = - FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); - ASSERT(bytes_written == sizeof(int)); - USE(bytes_written); - } - - void ReadChildError() { - const int kMaxMessageSize = 256; - char* message = DartUtils::ScopedCString(kMaxMessageSize); - if (message != nullptr) { - FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); - message[kMaxMessageSize - 1] = '\0'; - *os_error_message_ = message; - } else { - // Could not get error message. It will be nullptr. - ASSERT(*os_error_message_ == nullptr); - } - } - - void ClosePipe(int* fds) { - for (int i = 0; i < 2; i++) { - if (fds[i] != -1) { - close(fds[i]); - fds[i] = -1; - } - } - } - - void CloseAllPipes() { - ClosePipe(exec_control_); - ClosePipe(read_in_); - ClosePipe(read_err_); - ClosePipe(write_out_); - } - - int read_in_[2]; // Pipe for stdout to child process. - int read_err_[2]; // Pipe for stderr to child process. - int write_out_[2]; // Pipe for stdin to child process. - int exec_control_[2]; // Pipe to get the result from exec. - - char** program_arguments_; - char** program_environment_; - - Namespace* namespc_; - const char* path_; - const char* working_directory_; - ProcessStartMode mode_; - intptr_t* in_; - intptr_t* out_; - intptr_t* err_; - intptr_t* id_; - intptr_t* exit_event_; - char** os_error_message_; - - DISALLOW_ALLOCATION(); - DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); -}; - -int Process::Start(Namespace* namespc, - const char* path, - char* arguments[], - intptr_t arguments_length, - const char* working_directory, - char* environment[], - intptr_t environment_length, - ProcessStartMode mode, - intptr_t* in, - intptr_t* out, - intptr_t* err, - intptr_t* id, - intptr_t* exit_event, - char** os_error_message) { - ProcessStarter starter(namespc, path, arguments, arguments_length, - working_directory, environment, environment_length, - mode, in, out, err, id, exit_event, os_error_message); - return starter.Start(); -} - -static bool CloseProcessBuffers(struct pollfd* fds, int alive) { - int e = errno; - for (int i = 0; i < alive; i++) { - close(fds[i].fd); - } - errno = e; - return false; -} - -bool Process::Wait(intptr_t pid, - intptr_t in, - intptr_t out, - intptr_t err, - intptr_t exit_event, - ProcessResult* result) { - // Close input to the process right away. - close(in); - - // There is no return from this function using Dart_PropagateError - // as memory used by the buffer lists is freed through their - // destructors. - BufferList out_data; - BufferList err_data; - union { - uint8_t bytes[8]; - int32_t ints[2]; - } exit_code_data; - - struct pollfd fds[3]; - fds[0].fd = out; - fds[1].fd = err; - fds[2].fd = exit_event; - - for (int i = 0; i < 3; i++) { - fds[i].events = POLLIN; - } - - int alive = 3; - while (alive > 0) { - // Blocking call waiting for events from the child process. - if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) { - return CloseProcessBuffers(fds, alive); - } - - // Process incoming data. - for (int i = 0; i < alive; i++) { - if ((fds[i].revents & (POLLNVAL | POLLERR)) != 0) { - return CloseProcessBuffers(fds, alive); - } - if ((fds[i].revents & POLLIN) != 0) { - intptr_t avail = FDUtils::AvailableBytes(fds[i].fd); - if (fds[i].fd == out) { - if (!out_data.Read(out, avail)) { - return CloseProcessBuffers(fds, alive); - } - } else if (fds[i].fd == err) { - if (!err_data.Read(err, avail)) { - return CloseProcessBuffers(fds, alive); - } - } else if (fds[i].fd == exit_event) { - if (avail == 8) { - intptr_t b = - TEMP_FAILURE_RETRY(read(exit_event, exit_code_data.bytes, 8)); - if (b != 8) { - return CloseProcessBuffers(fds, alive); - } - } - } else { - UNREACHABLE(); - } - } - if ((fds[i].revents & POLLHUP) != 0) { - // Remove the pollfd from the list of pollfds. - close(fds[i].fd); - alive--; - if (i < alive) { - fds[i] = fds[alive]; - } - // Process the same index again. - i--; - continue; - } - } - } - - // All handles closed and all data read. - result->set_stdout_data(out_data.GetData()); - result->set_stderr_data(err_data.GetData()); - DEBUG_ASSERT(out_data.IsEmpty()); - DEBUG_ASSERT(err_data.IsEmpty()); - - // Calculate the exit code. - intptr_t exit_code = exit_code_data.ints[0]; - intptr_t negative = exit_code_data.ints[1]; - if (negative != 0) { - exit_code = -exit_code; - } - result->set_exit_code(exit_code); - - return true; -} - -bool Process::Kill(intptr_t id, int signal) { - return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1); -} - -void Process::TerminateExitCodeHandler() { - ExitCodeHandler::TerminateExitCodeThread(); -} - -intptr_t Process::CurrentProcessId() { - return static_cast(getpid()); -} - -static void SaveErrorAndClose(FILE* file) { - int actual_errno = errno; - fclose(file); - errno = actual_errno; -} - -int64_t Process::CurrentRSS() { - // The second value in /proc/self/statm is the current RSS in pages. - // It is not possible to use getrusage() because the interested fields are not - // implemented by the linux kernel. - FILE* statm = fopen("/proc/self/statm", "r"); - if (statm == nullptr) { - return -1; - } - int64_t current_rss_pages = 0; - int matches = fscanf(statm, "%*s%" Pd64 "", ¤t_rss_pages); - if (matches != 1) { - SaveErrorAndClose(statm); - return -1; - } - fclose(statm); - return current_rss_pages * getpagesize(); -} - -int64_t Process::MaxRSS() { - struct rusage usage; - usage.ru_maxrss = 0; - int r = getrusage(RUSAGE_SELF, &usage); - if (r < 0) { - return -1; - } - return usage.ru_maxrss * KB; -} - -static Mutex* signal_mutex = nullptr; -static SignalInfo* signal_handlers = nullptr; -static constexpr int kSignalsCount = 7; -static const int kSignals[kSignalsCount] = { - SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH, - SIGQUIT // Allow VMService to listen on SIGQUIT. -}; - -SignalInfo::~SignalInfo() { - close(fd_); -} - -static void SignalHandler(int signal) { - MutexLocker lock(signal_mutex); - const SignalInfo* handler = signal_handlers; - while (handler != nullptr) { - if (handler->signal() == signal) { - int value = 0; - VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1)); - } - handler = handler->next(); - } -} - -intptr_t Process::SetSignalHandler(intptr_t signal) { - bool found = false; - for (int i = 0; i < kSignalsCount; i++) { - if (kSignals[i] == signal) { - found = true; - break; - } - } - if (!found) { - return -1; - } - int fds[2]; - if (NO_RETRY_EXPECTED(pipe2(fds, O_CLOEXEC)) != 0) { - return -1; - } - if (!FDUtils::SetNonBlocking(fds[0])) { - close(fds[0]); - close(fds[1]); - return -1; - } - ThreadSignalBlocker blocker(kSignalsCount, kSignals); - MutexLocker lock(signal_mutex); - SignalInfo* handler = signal_handlers; - bool listen = true; - sa_handler_t oldact_handler = nullptr; - while (handler != nullptr) { - if (handler->signal() == signal) { - oldact_handler = handler->oldact(); - listen = false; - break; - } - handler = handler->next(); - } - if (listen) { - struct sigaction act = {}; - act.sa_handler = SignalHandler; - sigemptyset(&act.sa_mask); - for (int i = 0; i < kSignalsCount; i++) { - sigaddset(&act.sa_mask, kSignals[i]); - } - struct sigaction oldact = {}; - intptr_t status = NO_RETRY_EXPECTED(sigaction(signal, &act, &oldact)); - if (status < 0) { - close(fds[0]); - close(fds[1]); - return -1; - } - oldact_handler = oldact.sa_handler; - } - signal_handlers = - new SignalInfo(fds[1], signal, oldact_handler, signal_handlers); - return fds[0]; -} - -void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) { - ThreadSignalBlocker blocker(kSignalsCount, kSignals); - MutexLocker lock(signal_mutex); - SignalInfo* handler = signal_handlers; - sa_handler_t oldact_handler = SIG_DFL; - bool any_removed = false; - bool any_remaining = false; - while (handler != nullptr) { - bool remove = false; - if (handler->signal() == signal) { - if ((port == ILLEGAL_PORT) || (handler->port() == port)) { - if (signal_handlers == handler) { - signal_handlers = handler->next(); - } - oldact_handler = handler->oldact(); - handler->Unlink(); - remove = true; - any_removed = true; - } else { - any_remaining = true; - } - } - SignalInfo* next = handler->next(); - if (remove) { - delete handler; - } - handler = next; - } - if (any_removed && !any_remaining) { - struct sigaction act = {}; - act.sa_handler = oldact_handler; - VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, nullptr)); - } -} - -void Process::ClearSignalHandlerByFd(intptr_t fd, Dart_Port port) { - ThreadSignalBlocker blocker(kSignalsCount, kSignals); - MutexLocker lock(signal_mutex); - SignalInfo* handler = signal_handlers; - sa_handler_t oldact_handler = SIG_DFL; - bool any_remaining = false; - intptr_t signal = -1; - while (handler != nullptr) { - bool remove = false; - if (handler->fd() == fd) { - if ((port == ILLEGAL_PORT) || (handler->port() == port)) { - if (signal_handlers == handler) { - signal_handlers = handler->next(); - } - handler->Unlink(); - remove = true; - signal = handler->signal(); - } else { - any_remaining = true; - } - } - SignalInfo* next = handler->next(); - if (remove) { - delete handler; - } - handler = next; - } - if ((signal != -1) && !any_remaining) { - struct sigaction act = {}; - act.sa_handler = oldact_handler; - VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, nullptr)); - } -} - -void ProcessInfoList::Init() { - active_processes_ = nullptr; - ASSERT(ProcessInfoList::mutex_ == nullptr); - ProcessInfoList::mutex_ = new Mutex(); -} - -void ProcessInfoList::Cleanup() { - ASSERT(ProcessInfoList::mutex_ != nullptr); - delete ProcessInfoList::mutex_; - ProcessInfoList::mutex_ = nullptr; -} - -void ExitCodeHandler::Init() { - running_ = false; - process_count_ = 0; - terminate_done_ = false; - ASSERT(ExitCodeHandler::monitor_ == nullptr); - ExitCodeHandler::monitor_ = new Monitor(); -} - -void ExitCodeHandler::Cleanup() { - ASSERT(ExitCodeHandler::monitor_ != nullptr); - delete ExitCodeHandler::monitor_; - ExitCodeHandler::monitor_ = nullptr; -} - -void Process::Init() { - ExitCodeHandler::Init(); - ProcessInfoList::Init(); - - ASSERT(signal_mutex == nullptr); - signal_mutex = new Mutex(); - signal_handlers = nullptr; - - ASSERT(Process::global_exit_code_mutex_ == nullptr); - Process::global_exit_code_mutex_ = new Mutex(); -} - -void Process::Cleanup() { - ClearAllSignalHandlers(); - - ASSERT(signal_mutex != nullptr); - delete signal_mutex; - signal_mutex = nullptr; - - ASSERT(Process::global_exit_code_mutex_ != nullptr); - delete Process::global_exit_code_mutex_; - Process::global_exit_code_mutex_ = nullptr; - - ProcessInfoList::Cleanup(); - ExitCodeHandler::Cleanup(); -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc index 28bc053bb9d..f6d28cd89dc 100644 --- a/runtime/bin/process_linux.cc +++ b/runtime/bin/process_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/process.h" @@ -1162,4 +1162,4 @@ void Process::Cleanup() { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/security_context_android.cc b/runtime/bin/security_context_android.cc deleted file mode 100644 index 63a63a7a7a4..00000000000 --- a/runtime/bin/security_context_android.cc +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2017, 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. - -#if !defined(DART_IO_SECURE_SOCKET_DISABLED) - -#include "platform/globals.h" -#if defined(DART_HOST_OS_ANDROID) - -#include "bin/security_context.h" - -#include -#include -#include - -#include "bin/directory.h" -#include "bin/file.h" -#include "bin/secure_socket_filter.h" -#include "bin/secure_socket_utils.h" -#include "platform/syslog.h" - -namespace dart { -namespace bin { - -// The security context won't necessarily use the compiled-in root certificates, -// but since there is no way to update the size of the allocation after creating -// the weak persistent handle, we assume that it will. Note that when the -// root certs aren't compiled in, |root_certificates_pem_length| is 0. -const intptr_t SSLCertContext::kApproximateSize = - sizeof(SSLCertContext) + root_certificates_pem_length; - -void SSLCertContext::TrustBuiltinRoots() { - // First, try to use locations specified on the command line. - if (root_certs_file() != nullptr) { - LoadRootCertFile(root_certs_file()); - return; - } - if (root_certs_cache() != nullptr) { - LoadRootCertCache(root_certs_cache()); - return; - } - - // On Android, we don't compile in the trusted root certificates. Instead, - // we use the directory of trusted certificates already present on the device. - // This saves ~240KB from the size of the binary. This has the drawback that - // SSL_do_handshake will synchronously hit the filesystem looking for root - // certs during its trust evaluation. We call SSL_do_handshake directly from - // the Dart thread so that Dart code can be invoked from the "bad certificate" - // callback called by SSL_do_handshake. - const char* android_cacerts = "/system/etc/security/cacerts"; - LoadRootCertCache(android_cacerts); - return; -} - -void SSLCertContext::RegisterCallbacks(SSL* ssl) { - // No callbacks to register for implementations using BoringSSL's built-in - // verification mechanism. -} - -TrustEvaluateHandlerFunc SSLCertContext::GetTrustEvaluateHandler() const { - return nullptr; -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) - -#endif // !defined(DART_IO_SECURE_SOCKET_DISABLED) diff --git a/runtime/bin/security_context_linux.cc b/runtime/bin/security_context_linux.cc index 782de91ed18..dc89845a5a7 100644 --- a/runtime/bin/security_context_linux.cc +++ b/runtime/bin/security_context_linux.cc @@ -5,7 +5,7 @@ #if !defined(DART_IO_SECURE_SOCKET_DISABLED) #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/security_context.h" @@ -42,9 +42,21 @@ void SSLCertContext::TrustBuiltinRoots() { if (bypass_trusting_system_roots()) { if (SSL_LOG_STATUS) { - Syslog::Print("Bypass trusting Linux built-in roots\n"); + Syslog::Print("Bypass trusting built-in system roots\n"); } } else { +#if defined(DART_HOST_OS_ANDROID) + // On Android, we don't compile in the trusted root certificates. Instead, + // we use the directory of trusted certificates already present on the + // device. This saves ~240KB from the size of the binary. This has the + // drawback that SSL_do_handshake will synchronously hit the filesystem + // looking for root certs during its trust evaluation. We call + // SSL_do_handshake directly from the Dart thread so that Dart code can be + // invoked from the "bad certificate" callback called by SSL_do_handshake. + const char* android_cacerts = "/system/etc/security/cacerts"; + LoadRootCertCache(android_cacerts); + return; +#else // On Linux, we use the compiled-in trusted certs as a last resort. First, // we try to find the trusted certs in various standard locations. A good // discussion of the complexities of this endeavor can be found here: @@ -61,14 +73,16 @@ void SSLCertContext::TrustBuiltinRoots() { LoadRootCertCache(cachedir); return; } +#endif } - // Fall back on the compiled-in certs if the standard locations don't exist, - // or we aren't on Linux. +#if defined(DART_HOST_OS_LINUX) + // Fall back on the compiled-in certs if the standard locations don't exist. if (SSL_LOG_STATUS) { Syslog::Print("Trusting compiled-in roots\n"); } AddCompiledInCerts(); +#endif } void SSLCertContext::RegisterCallbacks(SSL* ssl) { @@ -83,6 +97,6 @@ TrustEvaluateHandlerFunc SSLCertContext::GetTrustEvaluateHandler() const { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #endif // !defined(DART_IO_SECURE_SOCKET_DISABLED) diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc deleted file mode 100644 index c3e30554d2f..00000000000 --- a/runtime/bin/socket_android.cc +++ /dev/null @@ -1,283 +0,0 @@ -// 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_ANDROID) - -#include "bin/socket.h" - -#include // NOLINT - -#include "bin/fdutils.h" -#include "platform/signal_blocker.h" -#include "platform/syslog.h" - -namespace dart { -namespace bin { - -Socket::Socket(intptr_t fd) - : ReferenceCounted(), - fd_(fd), - isolate_port_(Dart_GetMainPortId()), - port_(ILLEGAL_PORT), - udp_receive_buffer_(nullptr) {} - -void Socket::CloseFd() { - SetClosedFd(); -} - -void Socket::SetClosedFd() { - fd_ = kClosedFd; -} - -static intptr_t Create(const RawAddr& addr) { - intptr_t fd; - fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0)); - if (fd < 0) { - return -1; - } - if (!FDUtils::SetCloseOnExec(fd) || !FDUtils::SetNonBlocking(fd)) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - return fd; -} - -static intptr_t Connect(intptr_t fd, const RawAddr& addr) { - intptr_t result = TEMP_FAILURE_RETRY( - connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr))); - if ((result == 0) || (errno == EINPROGRESS)) { - return fd; - } - FDUtils::SaveErrorAndClose(fd); - return -1; -} - -intptr_t Socket::CreateConnect(const RawAddr& addr) { - intptr_t fd = Create(addr); - if (fd < 0) { - return fd; - } - - return Connect(fd, addr); -} - -intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) { - intptr_t fd = Create(addr); - if (fd < 0) { - return fd; - } - intptr_t result = TEMP_FAILURE_RETRY(connect( - fd, (struct sockaddr*)&addr.un, SocketAddress::GetAddrLength(addr))); - if (result == 0 || errno == EAGAIN) { - return fd; - } - FDUtils::SaveErrorAndClose(fd); - return -1; -} - -intptr_t Socket::CreateBindConnect(const RawAddr& addr, - const RawAddr& source_addr) { - intptr_t fd = Create(addr); - if (fd < 0) { - return fd; - } - - intptr_t result = TEMP_FAILURE_RETRY( - bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr))); - if (result != 0) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - - return Connect(fd, addr); -} - -intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr, - const RawAddr& source_addr) { - intptr_t fd = Create(addr); - if (fd < 0) { - return fd; - } - - intptr_t result = TEMP_FAILURE_RETRY( - bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr))); - if (result != 0) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - - result = TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)&addr.un, - SocketAddress::GetAddrLength(addr))); - if (result == 0 || errno == EAGAIN) { - return fd; - } - FDUtils::SaveErrorAndClose(fd); - return -1; -} - -intptr_t Socket::CreateBindDatagram(const RawAddr& addr, - bool reuseAddress, - bool reusePort, - int ttl) { - intptr_t fd; - - fd = NO_RETRY_EXPECTED(socket(addr.addr.sa_family, SOCK_DGRAM, IPPROTO_UDP)); - if (fd < 0) { - return -1; - } - - if (!FDUtils::SetCloseOnExec(fd)) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - - if (reuseAddress) { - int optval = 1; - VOID_NO_RETRY_EXPECTED( - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))); - } - - if (reusePort) { - // ignore reusePort - not supported on this platform. - Syslog::PrintErr( - "Dart Socket ERROR: %s:%d: `reusePort` not supported for " - "Android.", - __FILE__, __LINE__); - } - - if (!SocketBase::SetMulticastHops(fd, - addr.addr.sa_family == AF_INET - ? SocketAddress::TYPE_IPV4 - : SocketAddress::TYPE_IPV6, - ttl)) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - - if (NO_RETRY_EXPECTED( - bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - - if (!FDUtils::SetNonBlocking(fd)) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - return fd; -} - -intptr_t ServerSocket::CreateBindListen(const RawAddr& addr, - intptr_t backlog, - bool v6_only) { - intptr_t fd; - - fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0)); - if (fd < 0) { - return -1; - } - - if (!FDUtils::SetCloseOnExec(fd)) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - - int optval = 1; - VOID_NO_RETRY_EXPECTED( - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))); - - if (addr.ss.ss_family == AF_INET6) { - optval = v6_only ? 1 : 0; - VOID_NO_RETRY_EXPECTED( - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval))); - } - - if (NO_RETRY_EXPECTED( - bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - - // Test for invalid socket port 65535 (some browsers disallow it). - if ((SocketAddress::GetAddrPort(addr)) == 0 && - (SocketBase::GetPort(fd) == 65535)) { - // Don't close the socket until we have created a new socket, ensuring - // that we do not get the bad port number again. - intptr_t new_fd = CreateBindListen(addr, backlog, v6_only); - FDUtils::SaveErrorAndClose(fd); - return new_fd; - } - - if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - - if (!FDUtils::SetNonBlocking(fd)) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - return fd; -} - -intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr, - intptr_t backlog) { - intptr_t fd = Create(addr); - if (NO_RETRY_EXPECTED(bind(fd, (struct sockaddr*)&addr.un, - SocketAddress::GetAddrLength(addr))) < 0) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) { - FDUtils::SaveErrorAndClose(fd); - return -1; - } - return fd; -} - -bool ServerSocket::StartAccept(intptr_t fd) { - USE(fd); - return true; -} - -static bool IsTemporaryAcceptError(int error) { - // On Android a number of protocol errors should be treated as EAGAIN. - // These are the ones for TCP/IP. - return (error == EAGAIN) || (error == ENETDOWN) || (error == EPROTO) || - (error == ENOPROTOOPT) || (error == EHOSTDOWN) || (error == ENONET) || - (error == EHOSTUNREACH) || (error == EOPNOTSUPP) || - (error == ENETUNREACH); -} - -intptr_t ServerSocket::Accept(intptr_t fd) { - intptr_t socket; - struct sockaddr clientaddr; - socklen_t addrlen = sizeof(clientaddr); - socket = TEMP_FAILURE_RETRY(accept(fd, &clientaddr, &addrlen)); - if (socket == -1) { - if (IsTemporaryAcceptError(errno)) { - // We need to signal to the caller that this is actually not an - // error. We got woken up from the poll on the listening socket, - // but there is no connection ready to be accepted. - ASSERT(kTemporaryFailure != -1); - socket = kTemporaryFailure; - } - } else { - if (!FDUtils::SetCloseOnExec(socket)) { - FDUtils::SaveErrorAndClose(socket); - return -1; - } - if (!FDUtils::SetNonBlocking(socket)) { - FDUtils::SaveErrorAndClose(socket); - return -1; - } - } - return socket; -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/socket_base.h b/runtime/bin/socket_base.h index 702158fd8e4..a72a8b6dcd4 100644 --- a/runtime/bin/socket_base.h +++ b/runtime/bin/socket_base.h @@ -7,11 +7,9 @@ #include "platform/globals.h" // Declare the OS-specific types ahead of defining the generic class. -#if defined(DART_HOST_OS_ANDROID) -#include "bin/socket_base_android.h" -#elif defined(DART_HOST_OS_FUCHSIA) +#if defined(DART_HOST_OS_FUCHSIA) #include "bin/socket_base_fuchsia.h" -#elif defined(DART_HOST_OS_LINUX) +#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/socket_base_linux.h" #elif defined(DART_HOST_OS_MACOS) #include "bin/socket_base_macos.h" diff --git a/runtime/bin/socket_base_android.cc b/runtime/bin/socket_base_android.cc deleted file mode 100644 index c4f48dc82d6..00000000000 --- a/runtime/bin/socket_base_android.cc +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright (c) 2019, 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_ANDROID) - -#include "bin/socket_base.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bin/fdutils.h" -#include "bin/file.h" -#include "bin/ifaddrs-android.h" -#include "bin/socket_base_android.h" -#include "platform/signal_blocker.h" - -namespace dart { -namespace bin { - -SocketAddress::SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket) { - if (unnamed_unix_socket) { - // This is an unnamed unix domain socket. - as_string_[0] = 0; - } else if (sa->sa_family == AF_UNIX) { - struct sockaddr_un* un = ((struct sockaddr_un*)sa); - memmove(as_string_, un->sun_path, sizeof(un->sun_path)); - } else { - ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN); - if (!SocketBase::FormatNumericAddress(*reinterpret_cast(sa), - as_string_, INET6_ADDRSTRLEN)) { - as_string_[0] = 0; - } - } - socklen_t salen = - GetAddrLength(*reinterpret_cast(sa), unnamed_unix_socket); - memmove(reinterpret_cast(&addr_), sa, salen); -} - -bool SocketBase::Initialize() { - // Nothing to do on Android. - return true; -} - -bool SocketBase::FormatNumericAddress(const RawAddr& addr, - char* address, - int len) { - socklen_t salen = SocketAddress::GetAddrLength(addr); - return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, salen, address, len, - nullptr, 0, NI_NUMERICHOST)) == 0); -} - -bool SocketBase::IsBindError(intptr_t error_number) { - return error_number == EADDRINUSE || error_number == EADDRNOTAVAIL || - error_number == EINVAL; -} - -intptr_t SocketBase::Available(intptr_t fd) { - return FDUtils::AvailableBytes(fd); -} - -intptr_t SocketBase::Read(intptr_t fd, - void* buffer, - intptr_t num_bytes, - SocketOpKind sync) { - ASSERT(fd >= 0); - ssize_t read_bytes = TEMP_FAILURE_RETRY(read(fd, buffer, num_bytes)); - ASSERT(EAGAIN == EWOULDBLOCK); - if ((sync == kAsync) && (read_bytes == -1) && (errno == EWOULDBLOCK)) { - // If the read would block we need to retry and therefore return 0 - // as the number of bytes written. - read_bytes = 0; - } - return read_bytes; -} - -intptr_t SocketBase::RecvFrom(intptr_t fd, - void* buffer, - intptr_t num_bytes, - RawAddr* addr, - SocketOpKind sync) { - ASSERT(fd >= 0); - socklen_t addr_len = sizeof(addr->ss); - ssize_t read_bytes = TEMP_FAILURE_RETRY( - recvfrom(fd, buffer, num_bytes, 0, &addr->addr, &addr_len)); - if ((sync == kAsync) && (read_bytes == -1) && (errno == EWOULDBLOCK)) { - // If the read would block we need to retry and therefore return 0 - // as the number of bytes written. - read_bytes = 0; - } - return read_bytes; -} - -bool SocketControlMessage::is_file_descriptors_control_message() { - return false; -} - -intptr_t SocketBase::ReceiveMessage(intptr_t fd, - void* buffer, - int64_t* p_buffer_num_bytes, - SocketControlMessage** p_messages, - SocketOpKind sync, - OSError* p_oserror) { - errno = ENOSYS; - return -1; -} - -bool SocketBase::AvailableDatagram(intptr_t fd, - void* buffer, - intptr_t num_bytes) { - ASSERT(fd >= 0); - ssize_t read_bytes = TEMP_FAILURE_RETRY( - recvfrom(fd, buffer, num_bytes, MSG_PEEK, nullptr, nullptr)); - return read_bytes >= 0; -} - -intptr_t SocketBase::WriteImpl(intptr_t fd, - const void* buffer, - intptr_t num_bytes, - SocketOpKind sync) { - ASSERT(fd >= 0); - return TEMP_FAILURE_RETRY(write(fd, buffer, num_bytes)); -} - -intptr_t SocketBase::SendTo(intptr_t fd, - const void* buffer, - intptr_t num_bytes, - const RawAddr& addr, - SocketOpKind sync) { - ASSERT(fd >= 0); - ssize_t written_bytes = - TEMP_FAILURE_RETRY(sendto(fd, buffer, num_bytes, 0, &addr.addr, - SocketAddress::GetAddrLength(addr))); - ASSERT(EAGAIN == EWOULDBLOCK); - if ((sync == kAsync) && (written_bytes == -1) && (errno == EWOULDBLOCK)) { - // If the would block we need to retry and therefore return 0 as - // the number of bytes written. - written_bytes = 0; - } - return written_bytes; -} - -intptr_t SocketBase::SendMessage(intptr_t fd, - void* buffer, - size_t num_bytes, - SocketControlMessage* messages, - intptr_t num_messages, - SocketOpKind sync, - OSError* p_oserror) { - errno = ENOSYS; - return -1; -} - -bool SocketBase::GetSocketName(intptr_t fd, SocketAddress* p_sa) { - ASSERT(fd >= 0); - ASSERT(p_sa != nullptr); - RawAddr raw; - socklen_t size = sizeof(raw); - if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &size))) { - return false; - } - - // sockaddr_un contains sa_family_t sun_family and char[] sun_path. - // If size is the size of sa_family_t, this is an unnamed socket and - // sun_path contains garbage. - new (p_sa) SocketAddress(&raw.addr, - /*unnamed_unix_socket=*/size == sizeof(sa_family_t)); - return true; -} - -intptr_t SocketBase::GetPort(intptr_t fd) { - ASSERT(fd >= 0); - RawAddr raw; - socklen_t size = sizeof(raw); - if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &size))) { - return 0; - } - return SocketAddress::GetAddrPort(raw); -} - -SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) { - ASSERT(fd >= 0); - RawAddr raw; - socklen_t size = sizeof(raw); - if (NO_RETRY_EXPECTED(getpeername(fd, &raw.addr, &size))) { - return nullptr; - } - // sockaddr_un contains sa_family_t sun_family and char[] sun_path. - // If size is the size of sa_family_t, this is an unnamed socket and - // sun_path contains garbage. - if (size == sizeof(sa_family_t)) { - *port = 0; - return new SocketAddress(&raw.addr, true); - } - *port = SocketAddress::GetAddrPort(raw); - return new SocketAddress(&raw.addr); -} - -void SocketBase::GetError(intptr_t fd, OSError* os_error) { - int errorNumber; - socklen_t len = sizeof(errorNumber); - getsockopt(fd, SOL_SOCKET, SO_ERROR, reinterpret_cast(&errorNumber), - &len); - os_error->SetCodeAndMessage(OSError::kSystem, errorNumber); -} - -int SocketBase::GetType(intptr_t fd) { - struct stat buf; - int result = fstat(fd, &buf); - if (result == -1) { - return -1; - } - if (S_ISCHR(buf.st_mode)) { - return File::kTerminal; - } - if (S_ISFIFO(buf.st_mode)) { - return File::kPipe; - } - if (S_ISREG(buf.st_mode)) { - return File::kFile; - } - return File::kOther; -} - -intptr_t SocketBase::GetStdioHandle(intptr_t num) { - return num; -} - -AddressList* SocketBase::LookupAddress(const char* host, - int type, - OSError** os_error) { - // Perform a name lookup for a host name. - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = SocketAddress::FromType(type); - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_ADDRCONFIG; - hints.ai_protocol = IPPROTO_TCP; - struct addrinfo* info = nullptr; - int status = getaddrinfo(host, nullptr, &hints, &info); - if (status != 0) { - // We failed, try without AI_ADDRCONFIG. This can happen when looking up - // e.g. '::1', when there are no IPv6 addresses. - hints.ai_flags = 0; - status = getaddrinfo(host, nullptr, &hints, &info); - if (status != 0) { - ASSERT(*os_error == nullptr); - *os_error = - new OSError(status, gai_strerror(status), OSError::kGetAddressInfo); - return nullptr; - } - } - intptr_t count = 0; - for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) { - if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { - count++; - } - } - intptr_t i = 0; - AddressList* addresses = new AddressList(count); - for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) { - if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { - addresses->SetAt(i, new SocketAddress(c->ai_addr)); - i++; - } - } - freeaddrinfo(info); - return addresses; -} - -bool SocketBase::ReverseLookup(const RawAddr& addr, - char* host, - intptr_t host_len, - OSError** os_error) { - ASSERT(host_len >= NI_MAXHOST); - int status = NO_RETRY_EXPECTED( - getnameinfo(&addr.addr, SocketAddress::GetAddrLength(addr), host, - host_len, nullptr, 0, NI_NAMEREQD)); - if (status != 0) { - ASSERT(*os_error == nullptr); - *os_error = - new OSError(status, gai_strerror(status), OSError::kGetAddressInfo); - return false; - } - return true; -} - -bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) { - int result; - if (type == SocketAddress::TYPE_IPV4) { - result = inet_pton(AF_INET, address, &addr->in.sin_addr); - } else { - ASSERT(type == SocketAddress::TYPE_IPV6); - result = inet_pton(AF_INET6, address, &addr->in6.sin6_addr); - } - return (result == 1); -} - -bool SocketBase::RawAddrToString(RawAddr* addr, char* str) { - if (addr->addr.sa_family == AF_INET) { - return inet_ntop(AF_INET, &addr->in.sin_addr, str, INET_ADDRSTRLEN) != - nullptr; - } else { - ASSERT(addr->addr.sa_family == AF_INET6); - return inet_ntop(AF_INET6, &addr->in6.sin6_addr, str, INET6_ADDRSTRLEN) != - nullptr; - } -} - -static bool ShouldIncludeIfaAddrs(struct ifaddrs* ifa, int lookup_family) { - if (ifa->ifa_addr == nullptr) { - // OpenVPN's virtual device tun0. - return false; - } - int family = ifa->ifa_addr->sa_family; - return ((lookup_family == family) || - (((lookup_family == AF_UNSPEC) && - ((family == AF_INET) || (family == AF_INET6))))); -} - -AddressList* SocketBase::ListInterfaces( - int type, - OSError** os_error) { - struct ifaddrs* ifaddr; - - int status = NO_RETRY_EXPECTED(getifaddrs(&ifaddr)); - if (status != 0) { - ASSERT(*os_error == nullptr); - *os_error = - new OSError(status, gai_strerror(status), OSError::kGetAddressInfo); - return nullptr; - } - - int lookup_family = SocketAddress::FromType(type); - - intptr_t count = 0; - for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { - if (ShouldIncludeIfaAddrs(ifa, lookup_family)) { - count++; - } - } - - AddressList* addresses = - new AddressList(count); - int i = 0; - for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { - if (ShouldIncludeIfaAddrs(ifa, lookup_family)) { - char* ifa_name = DartUtils::ScopedCopyCString(ifa->ifa_name); - addresses->SetAt( - i, new InterfaceSocketAddress(ifa->ifa_addr, ifa_name, - if_nametoindex(ifa->ifa_name))); - i++; - } - } - freeifaddrs(ifaddr); - return addresses; -} - -void SocketBase::Close(intptr_t fd) { - ASSERT(fd >= 0); - close(fd); -} - -bool SocketBase::GetNoDelay(intptr_t fd, bool* enabled) { - int on; - socklen_t len = sizeof(on); - int err = NO_RETRY_EXPECTED(getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&on), &len)); - if (err == 0) { - *enabled = (on == 1); - } - return (err == 0); -} - -bool SocketBase::SetNoDelay(intptr_t fd, bool enabled) { - int on = enabled ? 1 : 0; - return NO_RETRY_EXPECTED(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&on), - sizeof(on))) == 0; -} - -bool SocketBase::GetMulticastLoop(intptr_t fd, - intptr_t protocol, - bool* enabled) { - uint8_t on; - socklen_t len = sizeof(on); - int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; - int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP - : IPV6_MULTICAST_LOOP; - if (NO_RETRY_EXPECTED(getsockopt(fd, level, optname, - reinterpret_cast(&on), &len)) == 0) { - *enabled = (on == 1); - return true; - } - return false; -} - -bool SocketBase::SetMulticastLoop(intptr_t fd, - intptr_t protocol, - bool enabled) { - int on = enabled ? 1 : 0; - int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; - int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP - : IPV6_MULTICAST_LOOP; - return NO_RETRY_EXPECTED(setsockopt( - fd, level, optname, reinterpret_cast(&on), sizeof(on))) == - 0; -} - -bool SocketBase::GetMulticastHops(intptr_t fd, intptr_t protocol, int* value) { - uint8_t v; - socklen_t len = sizeof(v); - int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; - int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_TTL - : IPV6_MULTICAST_HOPS; - if (NO_RETRY_EXPECTED(getsockopt(fd, level, optname, - reinterpret_cast(&v), &len)) == 0) { - *value = v; - return true; - } - return false; -} - -bool SocketBase::SetMulticastHops(intptr_t fd, intptr_t protocol, int value) { - int v = value; - int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; - int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_TTL - : IPV6_MULTICAST_HOPS; - return NO_RETRY_EXPECTED(setsockopt( - fd, level, optname, reinterpret_cast(&v), sizeof(v))) == 0; -} - -bool SocketBase::GetBroadcast(intptr_t fd, bool* enabled) { - int on; - socklen_t len = sizeof(on); - int err = NO_RETRY_EXPECTED(getsockopt(fd, SOL_SOCKET, SO_BROADCAST, - reinterpret_cast(&on), &len)); - if (err == 0) { - *enabled = (on == 1); - } - return (err == 0); -} - -bool SocketBase::SetBroadcast(intptr_t fd, bool enabled) { - int on = enabled ? 1 : 0; - return NO_RETRY_EXPECTED(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, - reinterpret_cast(&on), - sizeof(on))) == 0; -} - -bool SocketBase::SetOption(intptr_t fd, - int level, - int option, - const char* data, - int length) { - return NO_RETRY_EXPECTED(setsockopt(fd, level, option, data, length)) == 0; -} - -bool SocketBase::GetOption(intptr_t fd, - int level, - int option, - char* data, - unsigned int* length) { - socklen_t optlen = static_cast(*length); - auto result = NO_RETRY_EXPECTED(getsockopt(fd, level, option, data, &optlen)); - *length = static_cast(optlen); - return result == 0; -} - -bool SocketBase::JoinMulticast(intptr_t fd, - const RawAddr& addr, - const RawAddr&, - int interfaceIndex) { - int proto = (addr.addr.sa_family == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6; - struct group_req mreq; - mreq.gr_interface = interfaceIndex; - memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr)); - return NO_RETRY_EXPECTED( - setsockopt(fd, proto, MCAST_JOIN_GROUP, &mreq, sizeof(mreq))) == 0; -} - -bool SocketBase::LeaveMulticast(intptr_t fd, - const RawAddr& addr, - const RawAddr&, - int interfaceIndex) { - int proto = (addr.addr.sa_family == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6; - struct group_req mreq; - mreq.gr_interface = interfaceIndex; - memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr)); - return NO_RETRY_EXPECTED(setsockopt(fd, proto, MCAST_LEAVE_GROUP, &mreq, - sizeof(mreq))) == 0; -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/socket_base_android.h b/runtime/bin/socket_base_android.h deleted file mode 100644 index 9b10162667b..00000000000 --- a/runtime/bin/socket_base_android.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -#ifndef RUNTIME_BIN_SOCKET_BASE_ANDROID_H_ -#define RUNTIME_BIN_SOCKET_BASE_ANDROID_H_ - -#if !defined(RUNTIME_BIN_SOCKET_BASE_H_) -#error Do not include socket_base_android.h directly. Use socket_base.h. -#endif - -#include -#include -#include -#include - -#endif // RUNTIME_BIN_SOCKET_BASE_ANDROID_H_ diff --git a/runtime/bin/socket_base_linux.cc b/runtime/bin/socket_base_linux.cc index a02c47adfd9..570f03b23d2 100644 --- a/runtime/bin/socket_base_linux.cc +++ b/runtime/bin/socket_base_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/socket_base.h" @@ -145,4 +145,4 @@ bool SocketBase::LeaveMulticast(intptr_t fd, } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/socket_base_posix.cc b/runtime/bin/socket_base_posix.cc index 8f2a284de03..3838e6d11ee 100644 --- a/runtime/bin/socket_base_posix.cc +++ b/runtime/bin/socket_base_posix.cc @@ -3,11 +3,11 @@ // 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_MACOS) +#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX) || \ + defined(DART_HOST_OS_MACOS) #include "bin/socket_base.h" #include // NOLINT -#include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT @@ -18,6 +18,7 @@ #include "bin/fdutils.h" #include "bin/file.h" +#include "bin/ifaddrs.h" #include "bin/socket_base_macos.h" #include "platform/signal_blocker.h" diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc index bff69283e99..addd7f3cc9c 100644 --- a/runtime/bin/socket_linux.cc +++ b/runtime/bin/socket_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/socket.h" @@ -134,7 +134,7 @@ intptr_t Socket::CreateBindDatagram(const RawAddr& addr, } if (reusePort) { -#ifdef SO_REUSEPORT // Not all Linux versions support this. +#if !defined(DART_HOST_OS_ANDROID) && defined(SO_REUSEPORT) int optval = 1; int reuse_port_success = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); @@ -149,12 +149,12 @@ intptr_t Socket::CreateBindDatagram(const RawAddr& addr, Syslog::PrintErr("Dart Socket ERROR: %s:%d: %s.", __FILE__, __LINE__, Utils::StrError(errno, error_buf, kBufferSize)); } -#else // !defined SO_REUSEPORT +#else // defined(DART_HOST_OS_ANDROID) || !defined(SO_REUSEPORT) Syslog::PrintErr( - "Dart Socket ERROR: %s:%d: `reusePort` not available on this Linux " - "version.", + "Dart Socket ERROR: %s:%d: `reusePort` not supported on this " + "platform.", __FILE__, __LINE__); -#endif // SO_REUSEPORT +#endif // !defined(DART_HOST_OS_ANDROID) && defined(SO_REUSEPORT) } if (!SocketBase::SetMulticastHops(fd, @@ -277,4 +277,4 @@ intptr_t ServerSocket::Accept(intptr_t fd) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/stdio_android.cc b/runtime/bin/stdio_android.cc deleted file mode 100644 index 97d70dfa33a..00000000000 --- a/runtime/bin/stdio_android.cc +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2013, 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_ANDROID) - -#include "bin/stdio.h" - -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#include "bin/fdutils.h" -#include "platform/signal_blocker.h" - -namespace dart { -namespace bin { - -bool Stdin::ReadByte(intptr_t fd, int* byte) { - unsigned char b; - ssize_t s = TEMP_FAILURE_RETRY(read(fd, &b, 1)); - if (s < 0) { - return false; - } - *byte = (s == 0) ? -1 : b; - return true; -} - -bool Stdin::GetEchoMode(intptr_t fd, bool* enabled) { - struct termios term; - int status = NO_RETRY_EXPECTED(tcgetattr(fd, &term)); - if (status != 0) { - return false; - } - *enabled = ((term.c_lflag & ECHO) != 0); - return true; -} - -bool Stdin::SetEchoMode(intptr_t fd, bool enabled) { - struct termios term; - int status = NO_RETRY_EXPECTED(tcgetattr(fd, &term)); - if (status != 0) { - return false; - } - if (enabled) { - term.c_lflag |= ECHO; - } else { - term.c_lflag &= ~(ECHO); - } - status = NO_RETRY_EXPECTED(tcsetattr(fd, TCSANOW, &term)); - return (status == 0); -} - -bool Stdin::GetEchoNewlineMode(intptr_t fd, bool* enabled) { - struct termios term; - int status = NO_RETRY_EXPECTED(tcgetattr(fd, &term)); - if (status != 0) { - return false; - } - *enabled = ((term.c_lflag & ECHONL) != 0); - return true; -} - -bool Stdin::SetEchoNewlineMode(intptr_t fd, bool enabled) { - struct termios term; - int status = NO_RETRY_EXPECTED(tcgetattr(fd, &term)); - if (status != 0) { - return false; - } - if (enabled) { - term.c_lflag |= ECHONL; - } else { - term.c_lflag &= ~(ECHONL); - } - status = NO_RETRY_EXPECTED(tcsetattr(fd, TCSANOW, &term)); - return (status == 0); -} - -bool Stdin::GetLineMode(intptr_t fd, bool* enabled) { - struct termios term; - int status = NO_RETRY_EXPECTED(tcgetattr(fd, &term)); - if (status != 0) { - return false; - } - *enabled = ((term.c_lflag & ICANON) != 0); - return true; -} - -bool Stdin::SetLineMode(intptr_t fd, bool enabled) { - struct termios term; - int status = NO_RETRY_EXPECTED(tcgetattr(fd, &term)); - if (status != 0) { - return false; - } - if (enabled) { - term.c_lflag |= ICANON; - } else { - term.c_lflag &= ~(ICANON); - } - status = NO_RETRY_EXPECTED(tcsetattr(fd, TCSANOW, &term)); - return (status == 0); -} - -static bool TermIsKnownToSupportAnsi() { - const char* term = getenv("TERM"); - if (term == nullptr) { - return false; - } - - return strstr(term, "xterm") != nullptr || - strstr(term, "screen") != nullptr || strstr(term, "rxvt") != nullptr; -} - -bool Stdin::AnsiSupported(intptr_t fd, bool* supported) { - *supported = isatty(fd) && TermIsKnownToSupportAnsi(); - return true; -} - -bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) { - struct winsize w; - int status = NO_RETRY_EXPECTED(ioctl(fd, TIOCGWINSZ, &w)); - if ((status == 0) && ((w.ws_col != 0) || (w.ws_row != 0))) { - size[0] = w.ws_col; - size[1] = w.ws_row; - return true; - } - return false; -} - -bool Stdout::AnsiSupported(intptr_t fd, bool* supported) { - *supported = isatty(fd) && TermIsKnownToSupportAnsi(); - return true; -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/stdio_linux.cc b/runtime/bin/stdio_linux.cc index 2210e15e448..d96c09ade87 100644 --- a/runtime/bin/stdio_linux.cc +++ b/runtime/bin/stdio_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/stdio.h" @@ -136,4 +136,4 @@ bool Stdout::AnsiSupported(intptr_t fd, bool* supported) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/sync_socket_android.cc b/runtime/bin/sync_socket_android.cc deleted file mode 100644 index b38f8090eb9..00000000000 --- a/runtime/bin/sync_socket_android.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2017, 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_ANDROID) - -#include "bin/sync_socket.h" - -#include // NOLINT - -#include "bin/fdutils.h" -#include "bin/socket_base.h" -#include "platform/signal_blocker.h" - -namespace dart { -namespace bin { - -bool SynchronousSocket::Initialize() { - // Nothing to do on Android. - return true; -} - -static intptr_t Create(const RawAddr& addr) { - intptr_t fd; - intptr_t type = SOCK_STREAM; - fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, type, 0)); - if (fd < 0) { - return -1; - } - return fd; -} - -static intptr_t Connect(intptr_t fd, const RawAddr& addr) { - intptr_t result = TEMP_FAILURE_RETRY( - connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr))); - if (result == 0) { - return fd; - } - ASSERT(errno != EINPROGRESS); - FDUtils::SaveErrorAndClose(fd); - return -1; -} - -intptr_t SynchronousSocket::CreateConnect(const RawAddr& addr) { - intptr_t fd = Create(addr); - if (fd < 0) { - return fd; - } - return Connect(fd, addr); -} - -intptr_t SynchronousSocket::Available(intptr_t fd) { - return SocketBase::Available(fd); -} - -intptr_t SynchronousSocket::GetPort(intptr_t fd) { - return SocketBase::GetPort(fd); -} - -SocketAddress* SynchronousSocket::GetRemotePeer(intptr_t fd, intptr_t* port) { - return SocketBase::GetRemotePeer(fd, port); -} - -intptr_t SynchronousSocket::Read(intptr_t fd, - void* buffer, - intptr_t num_bytes) { - return SocketBase::Read(fd, buffer, num_bytes, SocketBase::kSync); -} - -intptr_t SynchronousSocket::Write(intptr_t fd, - const void* buffer, - intptr_t num_bytes) { - return SocketBase::Write(fd, buffer, num_bytes, SocketBase::kSync); -} - -void SynchronousSocket::ShutdownRead(intptr_t fd) { - VOID_NO_RETRY_EXPECTED(shutdown(fd, SHUT_RD)); -} - -void SynchronousSocket::ShutdownWrite(intptr_t fd) { - VOID_NO_RETRY_EXPECTED(shutdown(fd, SHUT_WR)); -} - -void SynchronousSocket::Close(intptr_t fd) { - return SocketBase::Close(fd); -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/sync_socket_linux.cc b/runtime/bin/sync_socket_linux.cc index 5c72f32d656..9c27088c74a 100644 --- a/runtime/bin/sync_socket_linux.cc +++ b/runtime/bin/sync_socket_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/sync_socket.h" @@ -89,4 +89,4 @@ void SynchronousSocket::Close(intptr_t fd) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h index ad56620c8f6..e41e8b620a5 100644 --- a/runtime/bin/thread.h +++ b/runtime/bin/thread.h @@ -18,11 +18,9 @@ class Monitor; // Declare the OS-specific types ahead of defining the generic classes. #if defined(DART_USE_ABSL) #include "bin/thread_absl.h" -#elif defined(DART_HOST_OS_ANDROID) -#include "bin/thread_android.h" #elif defined(DART_HOST_OS_FUCHSIA) #include "bin/thread_fuchsia.h" -#elif defined(DART_HOST_OS_LINUX) +#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include "bin/thread_linux.h" #elif defined(DART_HOST_OS_MACOS) #include "bin/thread_macos.h" diff --git a/runtime/bin/thread_android.cc b/runtime/bin/thread_android.cc deleted file mode 100644 index a31b19d57ea..00000000000 --- a/runtime/bin/thread_android.cc +++ /dev/null @@ -1,277 +0,0 @@ -// 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_ANDROID) && !defined(DART_USE_ABSL) - -#include "bin/thread.h" -#include "bin/thread_android.h" - -#include // NOLINT -#include // NOLINT - -#include "platform/assert.h" -#include "platform/utils.h" - -namespace dart { -namespace bin { - -#define VALIDATE_PTHREAD_RESULT(result) \ - if (result != 0) { \ - const int kBufferSize = 1024; \ - char error_message[kBufferSize]; \ - Utils::StrError(result, error_message, kBufferSize); \ - FATAL("pthread error: %d (%s)", result, error_message); \ - } - -#ifdef DEBUG -#define RETURN_ON_PTHREAD_FAILURE(result) \ - if (result != 0) { \ - const int kBufferSize = 1024; \ - char error_message[kBufferSize]; \ - Utils::StrError(result, error_message, kBufferSize); \ - fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \ - result, error_message); \ - return result; \ - } -#else -#define RETURN_ON_PTHREAD_FAILURE(result) \ - if (result != 0) { \ - return result; \ - } -#endif - -static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) { - struct timeval tv; - int64_t secs = micros / kMicrosecondsPerSecond; - int64_t remaining_micros = (micros - (secs * kMicrosecondsPerSecond)); - int result = gettimeofday(&tv, nullptr); - ASSERT(result == 0); - ts->tv_sec = tv.tv_sec + secs; - ts->tv_nsec = (tv.tv_usec + remaining_micros) * kNanosecondsPerMicrosecond; - if (ts->tv_nsec >= kNanosecondsPerSecond) { - ts->tv_sec += 1; - ts->tv_nsec -= kNanosecondsPerSecond; - } -} - -class ThreadStartData { - public: - ThreadStartData(const char* name, - Thread::ThreadStartFunction function, - uword parameter) - : name_(name), function_(function), parameter_(parameter) {} - - const char* name() const { return name_; } - Thread::ThreadStartFunction function() const { return function_; } - uword parameter() const { return parameter_; } - - private: - const char* name_; - Thread::ThreadStartFunction function_; - uword parameter_; - - DISALLOW_COPY_AND_ASSIGN(ThreadStartData); -}; - -// Dispatch to the thread start function provided by the caller. This trampoline -// is used to ensure that the thread is properly destroyed if the thread just -// exits. -static void* ThreadStart(void* data_ptr) { - ThreadStartData* data = reinterpret_cast(data_ptr); - - const char* name = data->name(); - Thread::ThreadStartFunction function = data->function(); - uword parameter = data->parameter(); - delete data; - - // Set the thread name. There is 16 bytes limit on the name (including \0). - // pthread_setname_np ignores names that are too long rather than truncating. - char truncated_name[16]; - snprintf(truncated_name, sizeof(truncated_name), "%s", name); - pthread_setname_np(pthread_self(), truncated_name); - - // Call the supplied thread start function handing it its parameters. - function(parameter); - - return nullptr; -} - -int Thread::Start(const char* name, - ThreadStartFunction function, - uword parameter) { - pthread_attr_t attr; - int result = pthread_attr_init(&attr); - RETURN_ON_PTHREAD_FAILURE(result); - - result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - RETURN_ON_PTHREAD_FAILURE(result); - - result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize()); - RETURN_ON_PTHREAD_FAILURE(result); - - ThreadStartData* data = new ThreadStartData(name, function, parameter); - - pthread_t tid; - result = pthread_create(&tid, &attr, ThreadStart, data); - RETURN_ON_PTHREAD_FAILURE(result); - - result = pthread_attr_destroy(&attr); - RETURN_ON_PTHREAD_FAILURE(result); - - return 0; -} - -const ThreadId Thread::kInvalidThreadId = static_cast(0); - -intptr_t Thread::GetMaxStackSize() { - const int kStackSize = (128 * kWordSize * KB); - return kStackSize; -} - -ThreadId Thread::GetCurrentThreadId() { - return gettid(); -} - -bool Thread::Compare(ThreadId a, ThreadId b) { - return (a == b); -} - -Mutex::Mutex() { - pthread_mutexattr_t attr; - int result = pthread_mutexattr_init(&attr); - VALIDATE_PTHREAD_RESULT(result); - -#if defined(DEBUG) - result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); - VALIDATE_PTHREAD_RESULT(result); -#endif // defined(DEBUG) - - result = pthread_mutex_init(data_.mutex(), &attr); - // Verify that creating a pthread_mutex succeeded. - VALIDATE_PTHREAD_RESULT(result); - - result = pthread_mutexattr_destroy(&attr); - VALIDATE_PTHREAD_RESULT(result); -} - -Mutex::~Mutex() { - int result = pthread_mutex_destroy(data_.mutex()); - // Verify that the pthread_mutex was destroyed. - VALIDATE_PTHREAD_RESULT(result); -} - -void Mutex::Lock() { - int result = pthread_mutex_lock(data_.mutex()); - // Specifically check for dead lock to help debugging. - ASSERT(result != EDEADLK); - ASSERT(result == 0); // Verify no other errors. - // TODO(iposva): Do we need to track lock owners? -} - -bool Mutex::TryLock() { - int result = pthread_mutex_trylock(data_.mutex()); - // Return false if the lock is busy and locking failed. - if (result == EBUSY) { - return false; - } - ASSERT(result == 0); // Verify no other errors. - // TODO(iposva): Do we need to track lock owners? - return true; -} - -void Mutex::Unlock() { - // TODO(iposva): Do we need to track lock owners? - int result = pthread_mutex_unlock(data_.mutex()); - // Specifically check for wrong thread unlocking to aid debugging. - ASSERT(result != EPERM); - ASSERT(result == 0); // Verify no other errors. -} - -Monitor::Monitor() { - pthread_mutexattr_t mutex_attr; - int result = pthread_mutexattr_init(&mutex_attr); - VALIDATE_PTHREAD_RESULT(result); - -#if defined(DEBUG) - result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK); - VALIDATE_PTHREAD_RESULT(result); -#endif // defined(DEBUG) - - result = pthread_mutex_init(data_.mutex(), &mutex_attr); - VALIDATE_PTHREAD_RESULT(result); - - result = pthread_mutexattr_destroy(&mutex_attr); - VALIDATE_PTHREAD_RESULT(result); - - pthread_condattr_t cond_attr; - result = pthread_condattr_init(&cond_attr); - VALIDATE_PTHREAD_RESULT(result); - - result = pthread_cond_init(data_.cond(), &cond_attr); - VALIDATE_PTHREAD_RESULT(result); - - result = pthread_condattr_destroy(&cond_attr); - VALIDATE_PTHREAD_RESULT(result); -} - -Monitor::~Monitor() { - int result = pthread_mutex_destroy(data_.mutex()); - VALIDATE_PTHREAD_RESULT(result); - - result = pthread_cond_destroy(data_.cond()); - VALIDATE_PTHREAD_RESULT(result); -} - -void Monitor::Enter() { - int result = pthread_mutex_lock(data_.mutex()); - VALIDATE_PTHREAD_RESULT(result); - // TODO(iposva): Do we need to track lock owners? -} - -void Monitor::Exit() { - // TODO(iposva): Do we need to track lock owners? - int result = pthread_mutex_unlock(data_.mutex()); - VALIDATE_PTHREAD_RESULT(result); -} - -Monitor::WaitResult Monitor::Wait(int64_t millis) { - return WaitMicros(millis * kMicrosecondsPerMillisecond); -} - -Monitor::WaitResult Monitor::WaitMicros(int64_t micros) { - // TODO(iposva): Do we need to track lock owners? - Monitor::WaitResult retval = kNotified; - if (micros == kNoTimeout) { - // Wait forever. - int result = pthread_cond_wait(data_.cond(), data_.mutex()); - VALIDATE_PTHREAD_RESULT(result); - } else { - struct timespec ts; - ComputeTimeSpecMicros(&ts, micros); - int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts); - ASSERT((result == 0) || (result == ETIMEDOUT)); - if (result == ETIMEDOUT) { - retval = kTimedOut; - } - } - return retval; -} - -void Monitor::Notify() { - // TODO(iposva): Do we need to track lock owners? - int result = pthread_cond_signal(data_.cond()); - VALIDATE_PTHREAD_RESULT(result); -} - -void Monitor::NotifyAll() { - // TODO(iposva): Do we need to track lock owners? - int result = pthread_cond_broadcast(data_.cond()); - VALIDATE_PTHREAD_RESULT(result); -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) && !defined(DART_USE_ABSL) diff --git a/runtime/bin/thread_android.h b/runtime/bin/thread_android.h deleted file mode 100644 index 9be755f7fe6..00000000000 --- a/runtime/bin/thread_android.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -#ifndef RUNTIME_BIN_THREAD_ANDROID_H_ -#define RUNTIME_BIN_THREAD_ANDROID_H_ - -#if !defined(RUNTIME_BIN_THREAD_H_) -#error Do not include thread_android.h directly; use thread.h instead. -#endif - -#include - -#include "platform/assert.h" -#include "platform/globals.h" - -namespace dart { -namespace bin { - -typedef pthread_t ThreadId; - -class MutexData { - private: - MutexData() {} - ~MutexData() {} - - pthread_mutex_t* mutex() { return &mutex_; } - - pthread_mutex_t mutex_; - - friend class Mutex; - - DISALLOW_ALLOCATION(); - DISALLOW_COPY_AND_ASSIGN(MutexData); -}; - -class MonitorData { - private: - MonitorData() {} - ~MonitorData() {} - - pthread_mutex_t* mutex() { return &mutex_; } - pthread_cond_t* cond() { return &cond_; } - - pthread_mutex_t mutex_; - pthread_cond_t cond_; - - friend class Monitor; - - DISALLOW_ALLOCATION(); - DISALLOW_COPY_AND_ASSIGN(MonitorData); -}; - -} // namespace bin -} // namespace dart - -#endif // RUNTIME_BIN_THREAD_ANDROID_H_ diff --git a/runtime/bin/thread_linux.cc b/runtime/bin/thread_linux.cc index 2b7aaff852d..409131bda4a 100644 --- a/runtime/bin/thread_linux.cc +++ b/runtime/bin/thread_linux.cc @@ -3,7 +3,8 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL) +#if (defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)) && \ + !defined(DART_USE_ABSL) #include "bin/thread.h" #include "bin/thread_linux.h" @@ -277,4 +278,5 @@ void Monitor::NotifyAll() { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL) +#endif // (defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)) && \ + // !defined(DART_USE_ABSL) diff --git a/runtime/bin/utils_android.cc b/runtime/bin/utils_android.cc deleted file mode 100644 index f8970843495..00000000000 --- a/runtime/bin/utils_android.cc +++ /dev/null @@ -1,114 +0,0 @@ -// 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_ANDROID) - -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#include "bin/utils.h" -#include "platform/assert.h" -#include "platform/utils.h" - -namespace dart { -namespace bin { - -OSError::OSError() : sub_system_(kSystem), code_(0), message_(nullptr) { - Reload(); -} - -void OSError::Reload() { - SetCodeAndMessage(kSystem, errno); -} - -void OSError::SetCodeAndMessage(SubSystem sub_system, int code) { - set_sub_system(sub_system); - set_code(code); - if (sub_system == kSystem) { - const int kBufferSize = 1024; - char error_message[kBufferSize]; - Utils::StrError(code, error_message, kBufferSize); - SetMessage(error_message); - } else if (sub_system == kGetAddressInfo) { - SetMessage(gai_strerror(code)); - } else { - UNREACHABLE(); - } -} - -const char* StringUtils::ConsoleStringToUtf8(const char* str, - intptr_t len, - intptr_t* result_len) { - return nullptr; -} - -const char* StringUtils::Utf8ToConsoleString(const char* utf8, - intptr_t len, - intptr_t* result_len) { - return nullptr; -} - -char* StringUtils::ConsoleStringToUtf8(char* str, - intptr_t len, - intptr_t* result_len) { - return nullptr; -} - -char* StringUtils::Utf8ToConsoleString(char* utf8, - intptr_t len, - intptr_t* result_len) { - return nullptr; -} - -bool ShellUtils::GetUtf8Argv(int argc, char** argv) { - return false; -} - -void TimerUtils::InitOnce() {} - -int64_t TimerUtils::GetCurrentMonotonicMillis() { - return GetCurrentMonotonicMicros() / 1000; -} - -int64_t TimerUtils::GetCurrentMonotonicMicros() { - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - UNREACHABLE(); - return 0; - } - // Convert to microseconds. - int64_t result = ts.tv_sec; - result *= kMicrosecondsPerSecond; - result += (ts.tv_nsec / kNanosecondsPerMicrosecond); - return result; -} - -void TimerUtils::Sleep(int64_t millis) { - struct timespec req; // requested. - struct timespec rem; // remainder. - int64_t micros = millis * kMicrosecondsPerMillisecond; - int64_t seconds = micros / kMicrosecondsPerSecond; - micros = micros - seconds * kMicrosecondsPerSecond; - int64_t nanos = micros * kNanosecondsPerMicrosecond; - req.tv_sec = seconds; - req.tv_nsec = nanos; - while (true) { - int r = nanosleep(&req, &rem); - if (r == 0) { - break; - } - // We should only ever see an interrupt error. - ASSERT(errno == EINTR); - // Copy remainder into requested and repeat. - req = rem; - } -} - -} // namespace bin -} // namespace dart - -#endif // defined(DART_HOST_OS_ANDROID) diff --git a/runtime/bin/utils_linux.cc b/runtime/bin/utils_linux.cc index 721a5e4d005..29109362838 100644 --- a/runtime/bin/utils_linux.cc +++ b/runtime/bin/utils_linux.cc @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" -#if defined(DART_HOST_OS_LINUX) +#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) #include // NOLINT #include // NOLINT @@ -110,4 +110,4 @@ void TimerUtils::Sleep(int64_t millis) { } // namespace bin } // namespace dart -#endif // defined(DART_HOST_OS_LINUX) +#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)