diff --git a/DEPS b/DEPS index 0e3627926a1d4..0fe5d5782d56f 100644 --- a/DEPS +++ b/DEPS @@ -26,9 +26,9 @@ vars = { # Note: When updating the Dart revision, ensure that all entries that are # dependencies of dart are also updated - 'dart_revision': '39ae4337dd8b6b1a66e7b7dc5142efffef3dd6ed', + 'dart_revision': 'aed6dd844d3f49acf97294e45d0ec9cfeaf6f508', 'dart_boringssl_revision': 'daeafc22c66ad48f6b32fc8d3362eb9ba31b774e', - 'dart_observatory_packages_revision': 'e5e1e543bea10d4bed95b22ad3e7aa2b20a23584', + 'dart_observatory_packages_revision': 'a01235b5b71df27b602dae4676d0bf771cbe7fa2', 'dart_root_certificates_revision': 'aed07942ce98507d2be28cbd29e879525410c7fc', 'buildtools_revision': '565d04e8741429fb1b4f26d102f2c6c3b849edeb', diff --git a/flutter/tonic/dart_message_handler.cc b/flutter/tonic/dart_message_handler.cc index 58a4876334ee3..69cfd0f5f3cf7 100644 --- a/flutter/tonic/dart_message_handler.cc +++ b/flutter/tonic/dart_message_handler.cc @@ -108,7 +108,11 @@ void DartMessageHandler::OnHandleMessage(DartState* dart_state) { void DartMessageHandler::MessageNotifyCallback(Dart_Isolate dest_isolate) { auto dart_state = DartState::From(dest_isolate); - FTL_CHECK(dart_state); + if (!dart_state) { + // The callback data for an isolate can be null if the isolate is in the + // middle of being shutdown. + return; + } dart_state->message_handler().OnMessage(dart_state); } diff --git a/sky/engine/core/script/dart_controller.cc b/sky/engine/core/script/dart_controller.cc index c9fa6fa11dbc9..3c62753828c17 100644 --- a/sky/engine/core/script/dart_controller.cc +++ b/sky/engine/core/script/dart_controller.cc @@ -49,6 +49,8 @@ DartController::~DartController() { if (ui_dart_state_) { // Don't use a tonic::DartIsolateScope here since we never exit the isolate. Dart_EnterIsolate(ui_dart_state_->isolate()); + // Clear the message notify callback. + Dart_SetMessageNotifyCallback(nullptr); Dart_ShutdownIsolate(); // deletes ui_dart_state_ ui_dart_state_ = nullptr; } diff --git a/sky/engine/core/script/dart_init.cc b/sky/engine/core/script/dart_init.cc index a18095053b186..e46e83dc14d1e 100644 --- a/sky/engine/core/script/dart_init.cc +++ b/sky/engine/core/script/dart_init.cc @@ -155,8 +155,7 @@ bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) { since_ms - (since_seconds * base::Time::kMillisecondsPerSecond); base::Time since_time = base::Time::FromTimeT(since_seconds) + base::TimeDelta::FromMilliseconds(since_milliseconds); - // TODO(johnmccutchan): Remove 'true ||' after Todd's fix has landed. - return true || file_info.last_modified > since_time; + return file_info.last_modified > since_time; } void ThreadExitCallback() { diff --git a/sky/engine/core/script/directory_asset_bundle.h b/sky/engine/core/script/directory_asset_bundle.h index ea0453d7a855a..d8cc17fe84152 100644 --- a/sky/engine/core/script/directory_asset_bundle.h +++ b/sky/engine/core/script/directory_asset_bundle.h @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef SKY_ENGINE_CORE_SCRIPT_DIRECTORY_ASSET_BUNDLE_H_ +#define SKY_ENGINE_CORE_SCRIPT_DIRECTORY_ASSET_BUNDLE_H_ + #include "base/files/file_path.h" #include "base/memory/weak_ptr.h" #include "mojo/public/cpp/bindings/interface_request.h" @@ -35,3 +38,5 @@ class DirectoryAssetBundleService : public mojo::asset_bundle::AssetBundle { }; } // namespace blink + +#endif // SKY_ENGINE_CORE_SCRIPT_DIRECTORY_ASSET_BUNDLE_H_ \ No newline at end of file diff --git a/sky/shell/platform_view.h b/sky/shell/platform_view.h index e2920899472f3..bb872bc865355 100644 --- a/sky/shell/platform_view.h +++ b/sky/shell/platform_view.h @@ -71,6 +71,10 @@ class PlatformView { virtual void Resize(const SkISize& size); + Engine& engine() { + return *engine_; + } + protected: Config config_; SurfaceConfig surface_config_; diff --git a/sky/shell/platform_view_service_protocol.cc b/sky/shell/platform_view_service_protocol.cc index 917bfdf4f1731..c2cb9602a8b4e 100644 --- a/sky/shell/platform_view_service_protocol.cc +++ b/sky/shell/platform_view_service_protocol.cc @@ -4,11 +4,79 @@ #include "sky/shell/platform_view_service_protocol.h" +#include + +#include "base/strings/string_util.h" #include "sky/shell/shell.h" namespace sky { namespace shell { +namespace { + +static intptr_t KeyIndex(const char** param_keys, + intptr_t num_params, + const char* key) { + if (param_keys == NULL) { + return -1; + } + for (intptr_t i = 0; i < num_params; i++) { + if (strcmp(param_keys[i], key) == 0) { + return i; + } + } + return -1; +} + +static const char* ValueForKey(const char** param_keys, + const char** param_values, + intptr_t num_params, + const char* key) { + intptr_t index = KeyIndex(param_keys, num_params, key); + if (index < 0) { + return NULL; + } + return param_values[index]; +} + +static bool ErrorMissingParameter(const char** json_object, + const char* name) { + const intptr_t kInvalidParams = -32602; + std::stringstream response; + response << "{\"code\":" << std::to_string(kInvalidParams) << ","; + response << "\"message\":\"Invalid params\","; + response << "\"data\": {\"details\": \"" << name << "\"}}"; + *json_object = strdup(response.str().c_str()); + return false; +} + +static bool ErrorBadParameter(const char** json_object, + const char* name, + const char* value) { + const intptr_t kInvalidParams = -32602; + std::stringstream response; + response << "{\"code\":" << std::to_string(kInvalidParams) << ","; + response << "\"message\":\"Invalid params\","; + response << "\"data\": {\"details\": \"parameter: " << name << " has a bad "; + response << "value: " << value << "\"}}"; + *json_object = strdup(response.str().c_str()); + return false; +} + +static bool ErrorUnknownView(const char** json_object, + const char* view_id) { + const intptr_t kInvalidParams = -32602; + std::stringstream response; + response << "{\"code\":" << std::to_string(kInvalidParams) << ","; + response << "\"message\":\"Invalid params\","; + response << "\"data\": {\"details\": \"view not found: " << view_id << "\"}}"; + *json_object = strdup(response.str().c_str()); + return false; +} + +} // namespace + + void PlatformViewServiceProtocol::RegisterHook(bool running_precompiled_code) { if (running_precompiled_code) { return; @@ -30,8 +98,53 @@ bool PlatformViewServiceProtocol::RunInView(const char* method, intptr_t num_params, void* user_data, const char** json_object) { - // TODO(johnmccutchan): Implement this. - *json_object = strdup("{\"type\": \"Success\"}"); + const char* view_id = + ValueForKey(param_keys, param_values, num_params, "viewId"); + const char* asset_directory = + ValueForKey(param_keys, param_values, num_params, "assetDirectory"); + const char* main_script = + ValueForKey(param_keys, param_values, num_params, "mainScript"); + const char* packages_file = + ValueForKey(param_keys, param_values, num_params, "packagesFile"); + if (view_id == NULL) { + return ErrorMissingParameter(json_object, "viewId"); + } + if (!base::StartsWithASCII(view_id, "_flutterView/", true)) { + return ErrorBadParameter(json_object, "viewId", view_id); + } + if (asset_directory == NULL) { + return ErrorMissingParameter(json_object, "assetDirectory"); + } + if (main_script == NULL) { + return ErrorMissingParameter(json_object, "mainScript"); + } + if (packages_file == NULL) { + return ErrorMissingParameter(json_object, "packagesFile"); + } + + // Convert the actual flutter view hex id into a number. + uintptr_t view_id_as_num = + std::stoull((view_id + strlen("_flutterView/")), nullptr, 16); + + // Ask the Shell to run this script in the specified view. This will run a + // task on the UI thread before returning. + Shell& shell = Shell::Shared(); + bool view_existed = false; + shell.RunInPlatformView(view_id_as_num, + main_script, + packages_file, + asset_directory, + &view_existed); + + if (!view_existed) { + // If the view did not exist this request has definitely failed. + return ErrorUnknownView(json_object, view_id); + } else { + // The view existed and the run was requested. Success. + // TODO(johnmccutchan): Can we send back any launch errors here? + *json_object = strdup("{\"type\": \"Success\"}"); + return true; + } return true; } @@ -47,17 +160,16 @@ bool PlatformViewServiceProtocol::ListViews(const char* method, // Ask the Shell for the list of platform views. This will run a task on // the UI thread before returning. Shell& shell = Shell::Shared(); - std::vector> platform_views; - shell.WaitForPlatformViews(&platform_views); + std::vector platform_views; + shell.WaitForPlatformViewIds(&platform_views); std::stringstream response; response << "{\"type\":\"FlutterViewList\",\"views\":["; bool prefix_comma = false; for (auto it = platform_views.begin(); it != platform_views.end(); it++) { - PlatformView* view = it->get(); - if (!view) { - // Skip any platform views which have been deleted. + uintptr_t view_id = *it; + if (!view_id) { continue; } if (prefix_comma) { @@ -66,7 +178,7 @@ bool PlatformViewServiceProtocol::ListViews(const char* method, prefix_comma = true; } response << "{\"type\":\"FlutterView\", \"id\": \"_flutterView/"; - response << "0x" << std::hex << reinterpret_cast(view); + response << "0x" << std::hex << view_id; response << "\"}"; } response << "]}"; diff --git a/sky/shell/shell.cc b/sky/shell/shell.cc index 93d07d2305ff5..6c0323c71459c 100644 --- a/sky/shell/shell.cc +++ b/sky/shell/shell.cc @@ -182,12 +182,10 @@ void Shell::InitGpuThread() { gpu_thread_checker_.reset(new base::ThreadChecker()); } - void Shell::InitUIThread() { ui_thread_checker_.reset(new base::ThreadChecker()); } - void Shell::AddRasterizer(const base::WeakPtr& rasterizer) { DCHECK(gpu_thread_checker_ && gpu_thread_checker_->CalledOnValidThread()); rasterizers_.push_back(rasterizer); @@ -227,25 +225,82 @@ void Shell::GetPlatformViews( *platform_views = platform_views_; } -void Shell::WaitForPlatformViews( - std::vector>* platform_views) { +void Shell::WaitForPlatformViewIds( + std::vector* platform_view_ids) { base::WaitableEvent latch(false, false); ui_task_runner()->PostTask( FROM_HERE, - base::Bind(&Shell::WaitForPlatformViewsUIThread, + base::Bind(&Shell::WaitForPlatformViewsIdsUIThread, base::Unretained(this), - base::Unretained(platform_views), + base::Unretained(platform_view_ids), base::Unretained(&latch))); latch.Wait(); } -void Shell::WaitForPlatformViewsUIThread( - std::vector>* platform_views, +void Shell::WaitForPlatformViewsIdsUIThread( + std::vector* platform_view_ids, base::WaitableEvent* latch) { - GetPlatformViews(platform_views); + std::vector> platform_views; + GetPlatformViews(&platform_views); + for (auto it = platform_views.begin(); it != platform_views.end(); it++) { + PlatformView* view = it->get(); + if (!view) { + // Skip dead views. + continue; + } + platform_view_ids->push_back(reinterpret_cast(view)); + } + latch->Signal(); +} + +void Shell::RunInPlatformView(uintptr_t view_id, + const char* main_script, + const char* packages_file, + const char* asset_directory, + bool* view_existed) { + base::WaitableEvent latch(false, false); + DCHECK(view_id != 0); + DCHECK(main_script); + DCHECK(packages_file); + DCHECK(asset_directory); + DCHECK(view_existed); + + ui_task_runner()->PostTask( + FROM_HERE, + base::Bind(&Shell::RunInPlatformViewUIThread, + base::Unretained(this), + view_id, + std::string(main_script), + std::string(packages_file), + std::string(asset_directory), + base::Unretained(view_existed), + base::Unretained(&latch))); + + latch.Wait(); +} + +void Shell::RunInPlatformViewUIThread(uintptr_t view_id, + const std::string& main, + const std::string& packages, + const std::string& assets_directory, + bool* view_existed, + base::WaitableEvent* latch) { + DCHECK(ui_thread_checker_ && ui_thread_checker_->CalledOnValidThread()); + + *view_existed = false; + + for (auto it = platform_views_.begin(); it != platform_views_.end(); it++) { + PlatformView* view = it->get(); + if (reinterpret_cast(view) == view_id) { + *view_existed = true; + view->engine().RunFromSource(main, packages, assets_directory); + break; + } + } + latch->Signal(); } diff --git a/sky/shell/shell.h b/sky/shell/shell.h index f5c2962fe0d23..42ceb4ad73cec 100644 --- a/sky/shell/shell.h +++ b/sky/shell/shell.h @@ -60,8 +60,16 @@ class Shell { platform_views); // These APIs can be called from any thread. - void WaitForPlatformViews( - std::vector>* platform_views); + // Return the list of platform view ids at the time of this call. + void WaitForPlatformViewIds( + std::vector* platform_view_ids); + // Attempt to run a script inside a flutter view indicated by |view_id|. + // Will set |view_existed| to true if the view was found and false otherwise. + void RunInPlatformView(uintptr_t view_id, + const char* main_script, + const char* packages_file, + const char* asset_directory, + bool* view_existed); private: Shell(); @@ -69,10 +77,17 @@ class Shell { void InitGpuThread(); void InitUIThread(); - void WaitForPlatformViewsUIThread( - std::vector>* platform_views, + void WaitForPlatformViewsIdsUIThread( + std::vector* platform_views, base::WaitableEvent* latch); + void RunInPlatformViewUIThread(uintptr_t view_id, + const std::string& main, + const std::string& packages, + const std::string& assets_directory, + bool* view_existed, + base::WaitableEvent* latch); + std::unique_ptr gpu_thread_; std::unique_ptr ui_thread_; std::unique_ptr io_thread_; diff --git a/sky/shell/ui/engine.cc b/sky/shell/ui/engine.cc index 57d17c8b125c5..8aaa8fd98c3a6 100644 --- a/sky/shell/ui/engine.cc +++ b/sky/shell/ui/engine.cc @@ -15,6 +15,7 @@ #include "services/asset_bundle/zip_asset_bundle.h" #include "sky/engine/bindings/mojo_services.h" #include "sky/engine/core/script/dart_init.h" +#include "sky/engine/core/script/directory_asset_bundle.h" #include "sky/engine/core/script/ui_dart_state.h" #include "sky/engine/public/web/Sky.h" #include "sky/shell/dart/dart_library_provider_files.h" @@ -68,6 +69,32 @@ void Engine::BeginFrame(ftl::TimePoint frame_time) { sky_view_->BeginFrame(frame_time); } +void Engine::RunFromSource(const std::string& main, + const std::string& packages, + const std::string& assets_directory) { + TRACE_EVENT0("flutter", "Engine::RunFromSource"); + // Assets. + base::FilePath assets_directory_path = base::FilePath(assets_directory); + ConfigureDirectoryAssetBundle(assets_directory_path); + // .packages. + base::FilePath packages_path = base::FilePath(std::string(packages)); + if (packages_path.empty()) { + base::FilePath main_dir = base::FilePath(main).DirName(); + packages_path = main_dir.Append(FILE_PATH_LITERAL(".packages")); + if (!base::PathExists(packages_path)) { + packages_path = main_dir.Append(base::FilePath::kParentDirectory) + .Append(FILE_PATH_LITERAL(".packages")); + if (!base::PathExists(packages_path)) + packages_path = base::FilePath(); + } + } + DartLibraryProviderFiles* provider = new DartLibraryProviderFiles(); + dart_library_provider_.reset(provider); + if (!packages_path.empty()) + provider->LoadPackagesMap(packages_path); + RunFromLibrary(main); +} + void Engine::ConnectToEngine(mojo::InterfaceRequest request) { binding_.Bind(request.Pass()); } @@ -176,6 +203,11 @@ void Engine::ConfigureZipAssetBundle(const mojo::String& path) { ZipAssetService::Create(mojo::GetProxy(&root_bundle_), zip_asset_bundle_); } +void Engine::ConfigureDirectoryAssetBundle(const base::FilePath& path) { + blink::DirectoryAssetBundleService::Create( + mojo::GetProxy(&root_bundle_), path); +} + void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) { TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot"); diff --git a/sky/shell/ui/engine.h b/sky/shell/ui/engine.h index e01cff6bbe684..9046ecb8ce1a6 100644 --- a/sky/shell/ui/engine.h +++ b/sky/shell/ui/engine.h @@ -56,6 +56,10 @@ class Engine : public UIDelegate, void BeginFrame(ftl::TimePoint frame_time); + void RunFromSource(const std::string& main, + const std::string& packages, + const std::string& assets_directory); + private: // UIDelegate implementation: void ConnectToEngine(mojo::InterfaceRequest request) override; @@ -102,6 +106,7 @@ class Engine : public UIDelegate, void StartAnimatorIfPossible(); void ConfigureZipAssetBundle(const mojo::String& path); + void ConfigureDirectoryAssetBundle(const base::FilePath& path); Config config_; std::unique_ptr animator_;