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)