diff --git a/fml/BUILD.gn b/fml/BUILD.gn index 6dabcb446c912..7afe06d9b3ecd 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -4,9 +4,13 @@ source_set("fml") { sources = [ + "file.cc", + "file.h", "icu_util.cc", "icu_util.h", + "mapping.cc", "mapping.h", + "memory/thread_checker.h", "memory/weak_ptr.h", "memory/weak_ptr_internal.cc", "memory/weak_ptr_internal.h", @@ -14,8 +18,10 @@ source_set("fml") { "message_loop.h", "message_loop_impl.cc", "message_loop_impl.h", + "native_library.cc", + "native_library.h", + "paths.cc", "paths.h", - "task_observer.h", "task_runner.cc", "task_runner.h", "thread.cc", @@ -95,6 +101,10 @@ source_set("fml") { ] } + if (is_fuchsia) { + sources += [ "platform/fuchsia/paths_fuchsia.cc" ] + } + if (is_win) { sources += [ "platform/win/mapping_win.cc", @@ -103,9 +113,7 @@ source_set("fml") { "platform/win/paths_win.cc", ] } else { - sources += [ - "platform/posix/mapping_posix.cc", - ] + sources += [ "platform/posix/mapping_posix.cc" ] } } diff --git a/fml/file.cc b/fml/file.cc new file mode 100644 index 0000000000000..c1751bd3c2081 --- /dev/null +++ b/fml/file.cc @@ -0,0 +1,67 @@ +// Copyright 2018 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/fml/file.h" + +#include +#include +#include + +#include "lib/fxl/files/eintr_wrapper.h" + +namespace fml { + +fxl::UniqueFD OpenFile(const char* path, + OpenPermission permission, + bool is_directory) { + return OpenFile(fxl::UniqueFD{AT_FDCWD}, path, permission, is_directory); +} + +fxl::UniqueFD OpenFile(const fxl::UniqueFD& base_directory, + const char* path, + OpenPermission permission, + bool is_directory) { + if (path == nullptr) { + return fxl::UniqueFD{}; + } + + int flags = 0; + switch (permission) { + case OpenPermission::kRead: + flags = O_RDONLY; + break; + case OpenPermission::kWrite: + flags = O_WRONLY; + case OpenPermission::kReadWrite: + flags = O_RDWR; + break; + } + + if (is_directory) { + flags |= O_DIRECTORY; + } + + return fxl::UniqueFD{ + HANDLE_EINTR(::openat(base_directory.get(), path, flags))}; +} + +fxl::UniqueFD Duplicate(int descriptor) { + return fxl::UniqueFD{HANDLE_EINTR(::dup(descriptor))}; +} + +bool IsDirectory(const fxl::UniqueFD& directory) { + if (!directory.is_valid()) { + return false; + } + + struct stat stat_result = {}; + + if (::fstat(directory.get(), &stat_result) != 0) { + return false; + } + + return S_ISDIR(stat_result.st_mode); +} + +} // namespace fml diff --git a/fml/file.h b/fml/file.h new file mode 100644 index 0000000000000..e6a7420f6dbf9 --- /dev/null +++ b/fml/file.h @@ -0,0 +1,34 @@ +// Copyright 2018 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FML_FILE_H_ +#define FLUTTER_FML_FILE_H_ + +#include "lib/fxl/files/unique_fd.h" +#include "lib/fxl/macros.h" + +namespace fml { + +enum class OpenPermission { + kRead = 1, + kWrite = 1 << 1, + kReadWrite = kRead | kWrite, +}; + +fxl::UniqueFD OpenFile(const char* path, + OpenPermission permission, + bool is_directory = false); + +fxl::UniqueFD OpenFile(const fxl::UniqueFD& base_directory, + const char* path, + OpenPermission permission, + bool is_directory = false); + +fxl::UniqueFD Duplicate(int descriptor); + +bool IsDirectory(const fxl::UniqueFD& directory); + +} // namespace fml + +#endif // FLUTTER_FML_FILE_H_ diff --git a/fml/icu_util.cc b/fml/icu_util.cc index 093dc3d02b1bc..0c0acd06dbbdf 100644 --- a/fml/icu_util.cc +++ b/fml/icu_util.cc @@ -22,8 +22,6 @@ static constexpr char kPathSeparator = '\\'; static constexpr char kPathSeparator = '/'; #endif -static constexpr char kIcuDataFileName[] = "icudtl.dat"; - class ICUContext { public: ICUContext(const std::string& icu_data_path) : valid_(false) { @@ -34,15 +32,15 @@ class ICUContext { bool SetupMapping(const std::string& icu_data_path) { // Check if the explicit path specified exists. - auto overriden_path_mapping = std::make_unique(icu_data_path); - if (overriden_path_mapping->GetSize() != 0) { - mapping_ = std::move(overriden_path_mapping); + auto path_mapping = std::make_unique(icu_data_path, false); + if (path_mapping->GetSize() != 0) { + mapping_ = std::move(path_mapping); return true; } // Check to see if the mapping is in the resources bundle. if (PlatformHasResourcesBundle()) { - auto resource = GetResourceMapping(kIcuDataFileName); + auto resource = GetResourceMapping(icu_data_path); if (resource != nullptr && resource->GetSize() != 0) { mapping_ = std::move(resource); return true; @@ -57,10 +55,8 @@ class ICUContext { return false; } - // FIXME(chinmaygarde): There is no Path::Join in FXL. So a non-portable - // version is used here. Patch FXL and update. auto file = std::make_unique( - directory.second + kPathSeparator + kIcuDataFileName); + directory.second + kPathSeparator + icu_data_path, false); if (file->GetSize() != 0) { mapping_ = std::move(file); return true; @@ -96,7 +92,8 @@ class ICUContext { void InitializeICUOnce(const std::string& icu_data_path) { static ICUContext* context = new ICUContext(icu_data_path); - FXL_CHECK(context->IsValid()) << "Must be able to initialize the ICU context"; + FXL_CHECK(context->IsValid()) + << "Must be able to initialize the ICU context. Tried: " << icu_data_path; } std::once_flag g_icu_init_flag; diff --git a/fml/macros.h b/fml/macros.h new file mode 100644 index 0000000000000..ba46b9dda4b4d --- /dev/null +++ b/fml/macros.h @@ -0,0 +1,20 @@ +// Copyright 2018 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FML_MACROS_H_ +#define FLUTTER_FML_MACROS_H_ + +#include "lib/fxl/macros.h" + +#ifndef FML_USED_ON_EMBEDDER + +#define FML_EMBEDDER_ONLY [[deprecated]] + +#else // FML_USED_ON_EMBEDDER + +#define FML_EMBEDDER_ONLY + +#endif // FML_USED_ON_EMBEDDER + +#endif // FLUTTER_FML_MACROS_H_ diff --git a/fml/mapping.cc b/fml/mapping.cc new file mode 100644 index 0000000000000..97d7905015f61 --- /dev/null +++ b/fml/mapping.cc @@ -0,0 +1,20 @@ +// Copyright 2018 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/fml/mapping.h" + +namespace fml { + +DataMapping::DataMapping(std::vector data) : data_(std::move(data)) {} + +DataMapping::~DataMapping() = default; + +size_t DataMapping::GetSize() const { + return data_.size(); +} + +const uint8_t* DataMapping::GetMapping() const { + return data_.data(); +} +} // namespace fml diff --git a/fml/mapping.h b/fml/mapping.h index 8963b22a9c1f6..a6b76a46f4fba 100644 --- a/fml/mapping.h +++ b/fml/mapping.h @@ -7,6 +7,7 @@ #include #include +#include #include "lib/fxl/build_config.h" @@ -39,11 +40,11 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name); class FileMapping : public Mapping { public: - FileMapping(const std::string& path); + FileMapping(const std::string& path, bool executable = false); // fxl::UniqueFD isn't supported for Windows handles. #if !OS_WIN - FileMapping(const fxl::UniqueFD& fd); + FileMapping(const fxl::UniqueFD& fd, bool executable = false); #endif ~FileMapping() override; @@ -63,6 +64,22 @@ class FileMapping : public Mapping { FXL_DISALLOW_COPY_AND_ASSIGN(FileMapping); }; +class DataMapping : public Mapping { + public: + DataMapping(std::vector data); + + ~DataMapping() override; + + size_t GetSize() const override; + + const uint8_t* GetMapping() const override; + + private: + std::vector data_; + + FXL_DISALLOW_COPY_AND_ASSIGN(DataMapping); +}; + } // namespace fml #endif // FLUTTER_FML_MAPPING_H_ diff --git a/fml/memory/thread_checker.h b/fml/memory/thread_checker.h new file mode 100644 index 0000000000000..33a62ee153612 --- /dev/null +++ b/fml/memory/thread_checker.h @@ -0,0 +1,69 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A class for checking that the current thread is/isn't the same as an initial +// thread. + +#ifndef LIB_FXL_SYNCHRONIZATION_THREAD_CHECKER_H_ +#define LIB_FXL_SYNCHRONIZATION_THREAD_CHECKER_H_ + +#include "lib/fxl/build_config.h" + +#if defined(OS_WIN) +#include +#else +#include +#endif + +#include "lib/fxl/logging.h" +#include "lib/fxl/macros.h" + +namespace fml { + +// A simple class that records the identity of the thread that it was created +// on, and at later points can tell if the current thread is the same as its +// creation thread. This class is thread-safe. +// +// Note: Unlike Chromium's |base::ThreadChecker|, this is *not* Debug-only (so +// #ifdef it out if you want something Debug-only). (Rationale: Having a +// |CalledOnValidThread()| that lies in Release builds seems bad. Moreover, +// there's a small space cost to having even an empty class. ) +class ThreadChecker final { + public: +#if defined(OS_WIN) + ThreadChecker() : self_(GetCurrentThreadId()) {} + ~ThreadChecker() {} + + bool IsCreationThreadCurrent() const { return GetCurrentThreadId() == self_; } + + private: + DWORD self_; + +#else + ThreadChecker() : self_(pthread_self()) {} + ~ThreadChecker() {} + + // Returns true if the current thread is the thread this object was created + // on and false otherwise. + bool IsCreationThreadCurrent() const { + return !!pthread_equal(pthread_self(), self_); + } + + private: + pthread_t self_; +#endif +}; + +#ifndef NDEBUG +#define FML_DECLARE_THREAD_CHECKER(c) fml::ThreadChecker c +#define FML_DCHECK_CREATION_THREAD_IS_CURRENT(c) \ + FXL_DCHECK((c).IsCreationThreadCurrent()) +#else +#define FML_DECLARE_THREAD_CHECKER(c) +#define FML_DCHECK_CREATION_THREAD_IS_CURRENT(c) ((void)0) +#endif + +} // namespace fml + +#endif // LIB_FXL_SYNCHRONIZATION_THREAD_CHECKER_H_ diff --git a/fml/memory/weak_ptr.h b/fml/memory/weak_ptr.h index 5b85c531966b2..2b369952d7306 100644 --- a/fml/memory/weak_ptr.h +++ b/fml/memory/weak_ptr.h @@ -10,12 +10,17 @@ #include +#include "flutter/fml/memory/thread_checker.h" #include "flutter/fml/memory/weak_ptr_internal.h" #include "lib/fxl/logging.h" #include "lib/fxl/memory/ref_counted.h" namespace fml { +struct DebugThreadChecker { + FML_DECLARE_THREAD_CHECKER(checker); +}; + // Forward declaration, so |WeakPtr| can friend it. template class WeakPtrFactory; @@ -41,13 +46,17 @@ class WeakPtr { WeakPtr(const WeakPtr& r) = default; template - WeakPtr(const WeakPtr& r) : ptr_(r.ptr_), flag_(r.flag_) {} + WeakPtr(const WeakPtr& r) + : ptr_(static_cast(r.ptr_)), flag_(r.flag_), checker_(r.checker_) {} // Move constructor. WeakPtr(WeakPtr&& r) = default; template - WeakPtr(WeakPtr&& r) : ptr_(r.ptr_), flag_(std::move(r.flag_)) {} + WeakPtr(WeakPtr&& r) + : ptr_(static_cast(r.ptr_)), + flag_(std::move(r.flag_)), + checker_(r.checker_) {} ~WeakPtr() = default; @@ -65,16 +74,24 @@ class WeakPtr { // The following methods should only be called on the same thread as the // "originating" |WeakPtrFactory|. - explicit operator bool() const { return flag_ && flag_->is_valid(); } + explicit operator bool() const { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); + return flag_ && flag_->is_valid(); + } - T* get() const { return *this ? ptr_ : nullptr; } + T* get() const { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); + return *this ? ptr_ : nullptr; + } T& operator*() const { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); FXL_DCHECK(*this); return *get(); } T* operator->() const { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); FXL_DCHECK(*this); return get(); } @@ -85,11 +102,14 @@ class WeakPtr { friend class WeakPtrFactory; - explicit WeakPtr(T* ptr, fxl::RefPtr&& flag) - : ptr_(ptr), flag_(std::move(flag)) {} + explicit WeakPtr(T* ptr, + fxl::RefPtr&& flag, + DebugThreadChecker checker) + : ptr_(ptr), flag_(std::move(flag)), checker_(checker) {} T* ptr_; fxl::RefPtr flag_; + DebugThreadChecker checker_; // Copy/move construction/assignment supported. }; @@ -140,19 +160,22 @@ template class WeakPtrFactory { public: explicit WeakPtrFactory(T* ptr) : ptr_(ptr) { FXL_DCHECK(ptr_); } + ~WeakPtrFactory() { InvalidateWeakPtrs(); } // Gets a new weak pointer, which will be valid until either // |InvalidateWeakPtrs()| is called or this object is destroyed. WeakPtr GetWeakPtr() { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); if (!flag_) flag_ = fxl::MakeRefCounted(); - return WeakPtr(ptr_, flag_.Clone()); + return WeakPtr(ptr_, flag_.Clone(), checker_); } // Call this method to invalidate all existing weak pointers. (Note that // additional weak pointers can be produced even after this is called.) void InvalidateWeakPtrs() { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); if (!flag_) return; flag_->Invalidate(); @@ -162,13 +185,17 @@ class WeakPtrFactory { // Call this method to determine if any weak pointers exist. (Note that a // "false" result is definitive, but a "true" result may not be if weak // pointers are held/reset/destroyed/reassigned on other threads.) - bool HasWeakPtrs() const { return flag_ && !flag_->HasOneRef(); } + bool HasWeakPtrs() const { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); + return flag_ && !flag_->HasOneRef(); + } private: // Note: See weak_ptr_internal.h for an explanation of why we store the // pointer here, instead of in the "flag". T* const ptr_; fxl::RefPtr flag_; + DebugThreadChecker checker_; FXL_DISALLOW_COPY_AND_ASSIGN(WeakPtrFactory); }; diff --git a/fml/message_loop.cc b/fml/message_loop.cc index 4765cfa76558f..44a0e307c1dd1 100644 --- a/fml/message_loop.cc +++ b/fml/message_loop.cc @@ -55,7 +55,7 @@ void MessageLoop::Terminate() { loop_->DoTerminate(); } -fxl::RefPtr MessageLoop::GetTaskRunner() const { +fxl::RefPtr MessageLoop::GetTaskRunner() const { return task_runner_; } @@ -63,12 +63,12 @@ fxl::RefPtr MessageLoop::GetLoopImpl() const { return loop_; } -void MessageLoop::AddTaskObserver(TaskObserver* observer) { - loop_->AddTaskObserver(observer); +void MessageLoop::AddTaskObserver(intptr_t key, fxl::Closure callback) { + loop_->AddTaskObserver(key, callback); } -void MessageLoop::RemoveTaskObserver(TaskObserver* observer) { - loop_->RemoveTaskObserver(observer); +void MessageLoop::RemoveTaskObserver(intptr_t key) { + loop_->RemoveTaskObserver(key); } void MessageLoop::RunExpiredTasksNow() { diff --git a/fml/message_loop.h b/fml/message_loop.h index 87773619ccc51..3bfb1c40c6df7 100644 --- a/fml/message_loop.h +++ b/fml/message_loop.h @@ -5,7 +5,7 @@ #ifndef FLUTTER_FML_MESSAGE_LOOP_H_ #define FLUTTER_FML_MESSAGE_LOOP_H_ -#include "flutter/fml/task_observer.h" +#include "flutter/fml/macros.h" #include "lib/fxl/macros.h" #include "lib/fxl/tasks/task_runner.h" @@ -16,6 +16,7 @@ class MessageLoopImpl; class MessageLoop { public: + FML_EMBEDDER_ONLY static MessageLoop& GetCurrent(); bool IsValid() const; @@ -24,11 +25,11 @@ class MessageLoop { void Terminate(); - void AddTaskObserver(TaskObserver* observer); + void AddTaskObserver(intptr_t key, fxl::Closure callback); - void RemoveTaskObserver(TaskObserver* observer); + void RemoveTaskObserver(intptr_t key); - fxl::RefPtr GetTaskRunner() const; + fxl::RefPtr GetTaskRunner() const; // Exposed for the embedder shell which allows clients to poll for events // instead of dedicating a thread to the message loop. diff --git a/fml/message_loop_impl.cc b/fml/message_loop_impl.cc index cec9b7e448f1a..df885f3792d5f 100644 --- a/fml/message_loop_impl.cc +++ b/fml/message_loop_impl.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#define FML_USED_ON_EMBEDDER + #include "flutter/fml/message_loop_impl.h" #include @@ -11,35 +13,29 @@ #include "lib/fxl/build_config.h" #if OS_MACOSX - #include "flutter/fml/platform/darwin/message_loop_darwin.h" -using PlatformMessageLoopImpl = fml::MessageLoopDarwin; - #elif OS_ANDROID - #include "flutter/fml/platform/android/message_loop_android.h" -using PlatformMessageLoopImpl = fml::MessageLoopAndroid; - #elif OS_LINUX - #include "flutter/fml/platform/linux/message_loop_linux.h" -using PlatformMessageLoopImpl = fml::MessageLoopLinux; - #elif OS_WIN - #include "flutter/fml/platform/win/message_loop_win.h" -using PlatformMessageLoopImpl = fml::MessageLoopWin; - -#else - -#error This platform does not have a message loop implementation. - #endif namespace fml { fxl::RefPtr MessageLoopImpl::Create() { - return fxl::MakeRefCounted<::PlatformMessageLoopImpl>(); +#if OS_MACOSX + return fxl::MakeRefCounted(); +#elif OS_ANDROID + return fxl::MakeRefCounted(); +#elif OS_LINUX + return fxl::MakeRefCounted(); +#elif OS_WIN + return fxl::MakeRefCounted(); +#else + return nullptr; +#endif } MessageLoopImpl::MessageLoopImpl() : order_(0), terminated_(false) {} @@ -55,20 +51,19 @@ void MessageLoopImpl::RunExpiredTasksNow() { RunExpiredTasks(); } -void MessageLoopImpl::AddTaskObserver(TaskObserver* observer) { - FXL_DCHECK(observer != nullptr); +void MessageLoopImpl::AddTaskObserver(intptr_t key, fxl::Closure callback) { + FXL_DCHECK(callback != nullptr); FXL_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this) << "Message loop task observer must be added on the same thread as the " "loop."; - task_observers_.insert(observer); + task_observers_[key] = std::move(callback); } -void MessageLoopImpl::RemoveTaskObserver(TaskObserver* observer) { - FXL_DCHECK(observer != nullptr); +void MessageLoopImpl::RemoveTaskObserver(intptr_t key) { FXL_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this) << "Message loop task observer must be removed from the same thread as " "the loop."; - task_observers_.erase(observer); + task_observers_.erase(key); } void MessageLoopImpl::DoRun() { @@ -144,7 +139,7 @@ void MessageLoopImpl::RunExpiredTasks() { for (const auto& invocation : invocations) { invocation(); for (const auto& observer : task_observers_) { - observer->DidProcessTask(); + observer.second(); } } } diff --git a/fml/message_loop_impl.h b/fml/message_loop_impl.h index bfdb2064cb264..478cbd1f1a0be 100644 --- a/fml/message_loop_impl.h +++ b/fml/message_loop_impl.h @@ -7,9 +7,9 @@ #include #include +#include #include #include -#include #include #include "flutter/fml/message_loop.h" @@ -34,9 +34,9 @@ class MessageLoopImpl : public fxl::RefCountedThreadSafe { void PostTask(fxl::Closure task, fxl::TimePoint target_time); - void AddTaskObserver(TaskObserver* observer); + void AddTaskObserver(intptr_t key, fxl::Closure callback); - void RemoveTaskObserver(TaskObserver* observer); + void RemoveTaskObserver(intptr_t key); void DoRun(); @@ -71,7 +71,7 @@ class MessageLoopImpl : public fxl::RefCountedThreadSafe { using DelayedTaskQueue = std:: priority_queue, DelayedTaskCompare>; - std::set task_observers_; + std::map task_observers_; std::mutex delayed_tasks_mutex_; DelayedTaskQueue delayed_tasks_; size_t order_; diff --git a/fml/message_loop_unittests.cc b/fml/message_loop_unittests.cc index 11ea72c3900eb..cd2acd308b46a 100644 --- a/fml/message_loop_unittests.cc +++ b/fml/message_loop_unittests.cc @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#define FML_USED_ON_EMBEDDER + #include #include "flutter/fml/message_loop.h" +#include "flutter/fml/task_runner.h" #include "gtest/gtest.h" #include "lib/fxl/synchronization/waitable_event.h" @@ -244,22 +247,6 @@ TEST(MessageLoop, TIME_SENSITIVE(MultipleDelayedTasksWithDecreasingDeltas)) { ASSERT_EQ(checked, count); } -class CustomTaskObserver : public fml::TaskObserver { - public: - CustomTaskObserver(std::function lambda) : lambda_(lambda){}; - - ~CustomTaskObserver() override = default; - - void DidProcessTask() override { - if (lambda_) { - lambda_(); - } - }; - - private: - std::function lambda_; -}; - TEST(MessageLoop, TaskObserverFire) { bool started = false; bool terminated = false; @@ -269,8 +256,7 @@ TEST(MessageLoop, TaskObserverFire) { auto& loop = fml::MessageLoop::GetCurrent(); size_t task_count = 0; size_t obs_count = 0; - CustomTaskObserver obs( - PLATFORM_SPECIFIC_CAPTURE(&obs_count)() { obs_count++; }); + auto obs = PLATFORM_SPECIFIC_CAPTURE(&obs_count)() { obs_count++; }; for (size_t i = 0; i < count; i++) { loop.GetTaskRunner()->PostTask( PLATFORM_SPECIFIC_CAPTURE(&terminated, i, &task_count)() { @@ -282,7 +268,7 @@ TEST(MessageLoop, TaskObserverFire) { } }); } - loop.AddTaskObserver(&obs); + loop.AddTaskObserver(0, obs); loop.Run(); ASSERT_EQ(task_count, count); ASSERT_EQ(obs_count, count); diff --git a/fml/native_library.cc b/fml/native_library.cc new file mode 100644 index 0000000000000..e8fb8d61ac86c --- /dev/null +++ b/fml/native_library.cc @@ -0,0 +1,62 @@ +// Copyright 2017 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/fml/native_library.h" + +#include +#include + +namespace fml { + +NativeLibrary::NativeLibrary(const char* path) { + ::dlerror(); + handle_ = ::dlopen(path, RTLD_NOW); + const char* error = ::dlerror(); + if (error != nullptr) { + handle_ = nullptr; + FXL_LOG(ERROR) << "Could not open library '" << path << "' due to error '" + << error << "'."; + } +} + +NativeLibrary::NativeLibrary(void* handle, bool close_handle) + : handle_(handle), close_handle_(close_handle) {} + +NativeLibrary::~NativeLibrary() { + if (handle_ == nullptr) { + return; + } + + if (close_handle_) { + ::dlerror(); + if (::dlclose(handle_) != 0) { + handle_ = nullptr; + FXL_LOG(ERROR) << "Could not close library due to error '" << ::dlerror() + << "'."; + } + } +} + +void* NativeLibrary::GetHandle() const { + return handle_; +} + +fxl::RefPtr NativeLibrary::Create(const char* path) { + auto library = fxl::AdoptRef(new NativeLibrary(path)); + return library->GetHandle() != nullptr ? library : nullptr; +} + +fxl::RefPtr NativeLibrary::CreateForCurrentProcess() { + return fxl::AdoptRef(new NativeLibrary(RTLD_DEFAULT, false)); +} + +const uint8_t* NativeLibrary::ResolveSymbol(const char* symbol) { + auto resolved_symbol = static_cast(::dlsym(handle_, symbol)); + if (resolved_symbol == nullptr) { + FXL_DLOG(ERROR) << "Could not resolve symbol in library: " << symbol; + } + return resolved_symbol; +} + +} // namespace fml diff --git a/fml/native_library.h b/fml/native_library.h new file mode 100644 index 0000000000000..8ae3d71bad1ce --- /dev/null +++ b/fml/native_library.h @@ -0,0 +1,39 @@ +// Copyright 2017 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FML_NATIVE_LIBRARY_H_ +#define FLUTTER_FML_NATIVE_LIBRARY_H_ + +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/ref_counted.h" +#include "lib/fxl/memory/ref_ptr.h" + +namespace fml { +class NativeLibrary : public fxl::RefCountedThreadSafe { + public: + static fxl::RefPtr Create(const char* path); + + static fxl::RefPtr CreateForCurrentProcess(); + + const uint8_t* ResolveSymbol(const char* symbol); + + private: + void* handle_ = nullptr; + bool close_handle_ = true; + + NativeLibrary(const char* path); + + NativeLibrary(void* handle, bool close_handle); + + ~NativeLibrary(); + + void* GetHandle() const; + + FXL_DISALLOW_COPY_AND_ASSIGN(NativeLibrary); + FRIEND_REF_COUNTED_THREAD_SAFE(NativeLibrary); +}; + +} // namespace fml + +#endif // FLUTTER_FML_NATIVE_LIBRARY_H_ diff --git a/fml/paths.cc b/fml/paths.cc new file mode 100644 index 0000000000000..4687292b71f71 --- /dev/null +++ b/fml/paths.cc @@ -0,0 +1,25 @@ +// Copyright 2018 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/fml/paths.h" + +namespace fml { +namespace paths { + +std::string JoinPaths(std::initializer_list components) { + std::stringstream stream; + size_t i = 0; + const size_t size = components.size(); + for (const auto& component : components) { + i++; + stream << component; + if (i != size) { + stream << "/"; + } + } + return stream.str(); +} + +} // namespace paths +} // namespace fml diff --git a/fml/paths.h b/fml/paths.h index 8ec3b4b580476..0d4367654de4a 100644 --- a/fml/paths.h +++ b/fml/paths.h @@ -8,11 +8,15 @@ #include #include +#include "lib/fxl/strings/string_view.h" + namespace fml { namespace paths { std::pair GetExecutableDirectoryPath(); +std::string JoinPaths(std::initializer_list components); + } // namespace paths } // namespace fml diff --git a/fml/platform/darwin/resource_mapping_darwin.mm b/fml/platform/darwin/resource_mapping_darwin.mm index 5d1b9664e20bc..3ee100121ad0f 100644 --- a/fml/platform/darwin/resource_mapping_darwin.mm +++ b/fml/platform/darwin/resource_mapping_darwin.mm @@ -9,8 +9,8 @@ namespace fml { ResourceMappingDarwin::ResourceMappingDarwin(const std::string& resource) - : actual_([[[NSBundle mainBundle] pathForResource:@(resource.c_str()) ofType:nil] UTF8String]) { -} + : actual_([[[NSBundle mainBundle] pathForResource:@(resource.c_str()) ofType:nil] UTF8String], + false) {} ResourceMappingDarwin::~ResourceMappingDarwin() = default; diff --git a/fml/platform/fuchsia/paths_fuchsia.cc b/fml/platform/fuchsia/paths_fuchsia.cc new file mode 100644 index 0000000000000..20def9f34fae9 --- /dev/null +++ b/fml/platform/fuchsia/paths_fuchsia.cc @@ -0,0 +1,15 @@ +// Copyright 2018 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/fml/paths.h" + +namespace fml { +namespace paths { + +std::pair GetExecutableDirectoryPath() { + return {false, ""}; +} + +} // namespace paths +} // namespace fml diff --git a/fml/platform/posix/mapping_posix.cc b/fml/platform/posix/mapping_posix.cc index 07f7edb074ab9..a06c7815582f7 100644 --- a/fml/platform/posix/mapping_posix.cc +++ b/fml/platform/posix/mapping_posix.cc @@ -39,11 +39,11 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name) { return std::make_unique(resource_name); } -FileMapping::FileMapping(const std::string& path) - : FileMapping(fxl::UniqueFD{HANDLE_EINTR(::open(path.c_str(), O_RDONLY))}) { -} +FileMapping::FileMapping(const std::string& path, bool executable) + : FileMapping(fxl::UniqueFD{HANDLE_EINTR(::open(path.c_str(), O_RDONLY))}, + executable) {} -FileMapping::FileMapping(const fxl::UniqueFD& handle) +FileMapping::FileMapping(const fxl::UniqueFD& handle, bool executable) : size_(0), mapping_(nullptr) { if (!handle.is_valid()) { return; @@ -59,8 +59,13 @@ FileMapping::FileMapping(const fxl::UniqueFD& handle) return; } - auto mapping = ::mmap(nullptr, stat_buffer.st_size, PROT_READ, MAP_PRIVATE, - handle.get(), 0); + int flags = PROT_READ; + if (executable) { + flags |= PROT_EXEC; + } + + auto mapping = + ::mmap(nullptr, stat_buffer.st_size, flags, MAP_PRIVATE, handle.get(), 0); if (mapping == MAP_FAILED) { return; diff --git a/fml/task_observer.h b/fml/task_observer.h deleted file mode 100644 index 21697cf022005..0000000000000 --- a/fml/task_observer.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_FML_TASK_OBSERVER_H_ -#define FLUTTER_FML_TASK_OBSERVER_H_ - -#include "lib/fxl/macros.h" - -namespace fml { - -class TaskObserver { - public: - virtual ~TaskObserver() = default; - - virtual void DidProcessTask() = 0; -}; - -} // namespace fml - -#endif // FLUTTER_FML_TASK_OBSERVER_H_ diff --git a/fml/task_runner.cc b/fml/task_runner.cc index 3d13674d78c11..95f91de8e9124 100644 --- a/fml/task_runner.cc +++ b/fml/task_runner.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#define FML_USED_ON_EMBEDDER + #include "flutter/fml/task_runner.h" #include @@ -38,4 +40,14 @@ bool TaskRunner::RunsTasksOnCurrentThread() { return MessageLoop::GetCurrent().GetLoopImpl() == loop_; } +void TaskRunner::RunNowOrPostTask(fxl::RefPtr runner, + fxl::Closure task) { + FXL_DCHECK(runner); + if (runner->RunsTasksOnCurrentThread()) { + task(); + } else { + runner->PostTask(std::move(task)); + } +} + } // namespace fml diff --git a/fml/task_runner.h b/fml/task_runner.h index 20ea85e4e521b..3b3d2de01639d 100644 --- a/fml/task_runner.h +++ b/fml/task_runner.h @@ -13,7 +13,7 @@ namespace fml { class MessageLoopImpl; -class TaskRunner : public fxl::TaskRunner { +class TaskRunner final : public fxl::TaskRunner { public: void PostTask(fxl::Closure task) override; @@ -23,12 +23,15 @@ class TaskRunner : public fxl::TaskRunner { bool RunsTasksOnCurrentThread() override; + static void RunNowOrPostTask(fxl::RefPtr runner, + fxl::Closure task); + private: fxl::RefPtr loop_; TaskRunner(fxl::RefPtr loop); - ~TaskRunner(); + ~TaskRunner() override; FRIEND_MAKE_REF_COUNTED(TaskRunner); FRIEND_REF_COUNTED_THREAD_SAFE(TaskRunner); diff --git a/fml/thread.cc b/fml/thread.cc index a1500bfef46a4..de4ee6dd368a8 100644 --- a/fml/thread.cc +++ b/fml/thread.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#define FML_USED_ON_EMBEDDER + #include "flutter/fml/thread.h" #include "lib/fxl/build_config.h" @@ -22,7 +24,7 @@ namespace fml { Thread::Thread(const std::string& name) : joined_(false) { fxl::AutoResetWaitableEvent latch; - fxl::RefPtr runner; + fxl::RefPtr runner; thread_ = std::make_unique([&latch, &runner, name]() -> void { SetCurrentThreadName(name); fml::MessageLoop::EnsureInitializedForCurrentThread(); @@ -39,7 +41,7 @@ Thread::~Thread() { Join(); } -fxl::RefPtr Thread::GetTaskRunner() const { +fxl::RefPtr Thread::GetTaskRunner() const { return task_runner_; } @@ -84,7 +86,8 @@ void Thread::SetCurrentThreadName(const std::string& name) { } __except (EXCEPTION_CONTINUE_EXECUTION) { } #else -#error Unsupported Platform + FXL_DLOG(INFO) << "Could not set the thread name to '" << name + << "' on this platform."; #endif } diff --git a/fml/thread.h b/fml/thread.h index 44062f1032116..542871f788845 100644 --- a/fml/thread.h +++ b/fml/thread.h @@ -9,8 +9,8 @@ #include #include +#include "flutter/fml/task_runner.h" #include "lib/fxl/macros.h" -#include "lib/fxl/tasks/task_runner.h" namespace fml { @@ -20,13 +20,13 @@ class Thread { ~Thread(); - fxl::RefPtr GetTaskRunner() const; + fxl::RefPtr GetTaskRunner() const; void Join(); private: std::unique_ptr thread_; - fxl::RefPtr task_runner_; + fxl::RefPtr task_runner_; std::atomic_bool joined_; static void SetCurrentThreadName(const std::string& name);