From c50158f78baca535287a0ba455245681149169f9 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 31 Oct 2017 17:03:57 -0700 Subject: [PATCH] Support multiple shells in a single process. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Flutter Engine currently works by initializing a singleton shell instance. This shell has to be created on the platform thread. The shell is responsible for creating the 3 main threads used by Flutter (UI, IO, GPU) as well as initializing the Dart VM. The shell, references to task runners of the main threads as well as all snapshots used for VM initialization are stored in singleton objects. The Flutter shell only creates the threads, rasterizers, contexts, etc. to fully support a single Flutter application. Current support for multiple Flutter applications is achieved by making multiple applications share the same resources (via the platform views mechanism). This scheme has the following limitations: * The shell is a singleton and there is no way to tear it down. Once you run a Flutter application in a process, all resources managed by it will remain referenced till process termination. * The threads on which the shell performs its operations are all singletons. These threads are never torn down and multiple Flutter applications (if present) have to compete with one another on these threads. * Resources referenced by the Dart VM are leaked because the VM isn't shutdown even when there are no more Flutter views. * The shell as a target does not compile on Fuchsia. The Fuchsia content handler uses specific dependencies of the shell to rebuild all the shell dependencies on its own. This leads to differences in frame scheduling, VM setup, service protocol endpoint setup, tracing, etc.. Fuchsia is very much a second class citizen in this world. * Since threads and message loops are managed by the engine, the engine has to know about threading and platform message loop interop on each supported platform. Specific updates in this patch: * The shell is no longer a singleton and the embedder holds the unique reference to the shell. * Shell setup and teardown is deterministic. * Threads are no longer managed by the shell. Instead, the shell is given a task runner configuration by the embedder. * Since the shell does not own its threads, the embedder can control threads and the message loops operating on these threads. The shell is only given references to the task runners that execute tasks on these threads. * The shell only needs task runner references. These references can be to the same task runner. So, if the embedder thinks that a particular Flutter application would not need all the threads, it can pass references to the same task runner. This effectively makes Flutter application run in single threaded mode. There are some places in the shell that make synchronous calls, these sites have been updated to ensure that they don’t deadlock. * The test runner and the headless Dart code runner are now Flutter applications that are effectively single threaded (since they don’t have rendering concerns of big-boy Flutter application). * The embedder has to guarantee that the threads and outlive the shell. It is easy for the embedder to make that guarantee because shell termination is deterministic. * The embedder can create as many shell as it wants. Typically it creates a shell per Flutter application with its own task runner configuration. Most embedders obtain these task runners from threads dedicated to the shell. But, it is entirely possible that the embedder can obtain these task runners from a thread pool. * There can only be one Dart VM in the process. The numerous shell interact with one another to manage the VM lifecycle. Once the last shell goes away, the VM does as well and hence all resources associated with the VM are collected. * The shell as a target can now compile and run on Fuchsia. The current content handler has been removed from the Flutter engine source tree and a new implementation has been written that uses the new shell target. * Isolate management has been significantly overhauled. There are no owning references to Dart isolates within the shell. The VM owns the only strong reference to the Dart isolate. The isolate that has window bindings is now called the root isolate. Child isolates can now be created from the root isolate and their bindings and thread configurations are now inherited from the root isolate. * Terminating the shell terminates its root isolates as well as all the isolates spawned by this isolate. This is necessary be shell shutdown is deterministic and the embedder is free to collect the threads on which the isolates execute their tasks (and listen for mircrotasks flushes on). * Launching the root isolate is now significantly overhauled. The shell side (non-owning) reference to an isolate is now a little state machine and illegal state transitions should be impossible (barring construction issues). This is the only way to manage Dart isolates in the shell (the shell does not use the C API is dart_api.h anymore). * Once an isolate is launched, it must be prepared (and hence move to the ready phase) by associating a snapshot with the same. This snapshot can either be a precompiled snapshot, kernel snapshot, script snapshot or source file. Depending on the kind of data specified as a snapshot as well as the capabilities of the VM running in the process, isolate preparation can fail preparation with the right message. * Asset management has been significantly overhauled. All asset resolution goes through an abstract asset resolver interface. An asset manager implements this interface and manages one or more child asset resolvers. These asset resolvers typically resolve assets from directories, ZIP files (legacy FLX assets if provided), APK bundles, FDIO namespaces, etc… * Each launch of the shell requires a separate and fully configured asset resolver. This is necessary because launching isolates for the engine may require resolving snapshots as assets from the asset resolver. Asset resolvers can be shared by multiple launch instances in multiple shells and need to be thread safe. * References to the command line object have been removed from the shell. Instead, the shell only takes a settings object that may be configured from the command line. This makes it easy for embedders and platforms that don’t have a command line (Fuchsia) to configure the shell. Consequently, there is only one spot where the various switches are read from the command line (by the embedder and not the shell) to form the settings object. * All platform now respect the log tag (this was done only by Android till now) and each shell instance have its own log tag. This makes logs from multiple Flutter application in the same process (mainly Fuchsia) more easily decipherable. * The per shell IO task runner now has a new component that is unfortunately named the IOManager. This component manages the IO GrContext (used for asynchronous texture uploads) that cooperates with the GrContext on the GPU task runner associated with the shell. The IOManager is also responsible for flushing tasks that collect Skia objects that reference GPU resources during deterministic shell shutdown. * The embedder now has to be careful to only enable Blink on a single instance of the shell. Launching the legacy text layout and rendering engine multiple times is will trip assertions. The entirety of this runtime has been separated out into a separate object and can be removed in one go when the migration to libtxt is complete. * There is a new test target for the various C++ objects that the shell uses to interact with the Dart VM (the shell no longer use the C API in dart_api.h). This allows engine developers to test VM/Isolate initialization and teardown without having the setup a full shell instance. * There is a new test target for the testing a single shell instances without having to configure and launch an entire VM and associated root isolate. * Mac, Linux & Windows used to have different target that created the flutter_tester referenced by the tool. This has now been converted into a single target that compiles on all platforms. * WeakPointers vended by the fml::WeakPtrFactory(notice the difference between the same class in the fxl namespace) add threading checks on each use. This is enabled by getting rid of the “re-origination” feature of the WeakPtrFactory in the fxl namespace. The side effect of this is that all non-thread safe components have to be created, used and destroyed on the same thread. Numerous thread safety issues were caught by this extra assertion and have now been fixed. * Glossary of components that are only safe on a specific thread (and have the fml variants of the WeakPtrFactory): * Platform Thread: Shell * UI Thread: Engine, RuntimeDelegate, DartIsolate, Animator * GPU Thread: Rasterizer, Surface * IO Thread: IOManager This patch was reviewed in smaller chunks in the following pull requests. All comments from the pulls requests has been incorporated into this patch: * flutter/assets: https://github.com/flutter/engine/pull/4829 * flutter/common: https://github.com/flutter/engine/pull/4830 * flutter/content_handler: https://github.com/flutter/engine/pull/4831 * flutter/flow: https://github.com/flutter/engine/pull/4832 * flutter/fml: https://github.com/flutter/engine/pull/4833 * flutter/lib/snapshot: https://github.com/flutter/engine/pull/4834 * flutter/lib/ui: https://github.com/flutter/engine/pull/4835 * flutter/runtime: https://github.com/flutter/engine/pull/4836 * flutter/shell: https://github.com/flutter/engine/pull/4837 * flutter/synchronization: https://github.com/flutter/engine/pull/4838 * flutter/testing: https://github.com/flutter/engine/pull/4839 --- BUILD.gn | 74 +- DEPS | 2 +- assets/BUILD.gn | 12 +- assets/asset_manager.cc | 55 + assets/asset_manager.h | 47 + assets/asset_provider.h | 25 - assets/asset_resolver.h | 32 + assets/directory_asset_bundle.cc | 85 +- assets/directory_asset_bundle.h | 32 +- assets/unzipper_provider.cc | 21 - assets/unzipper_provider.h | 20 - assets/zip_asset_store.cc | 24 +- assets/zip_asset_store.h | 24 +- common/BUILD.gn | 5 +- common/settings.cc | 58 +- common/settings.h | 74 +- common/task_runners.cc | 48 + common/task_runners.h | 46 + common/threads.cc | 56 - common/threads.h | 48 - content_handler/BUILD.gn | 59 +- content_handler/README.md | 4 + content_handler/accessibility_bridge.cc | 15 +- content_handler/accessibility_bridge.h | 25 +- content_handler/app.cc | 174 --- content_handler/app.h | 64 - content_handler/application.cc | 313 +++++ content_handler/application.h | 97 ++ .../application_controller_impl.cc | 148 --- content_handler/application_controller_impl.h | 76 -- content_handler/application_runner.cc | 90 ++ content_handler/application_runner.h | 79 ++ content_handler/compositor_context.cc | 86 ++ content_handler/compositor_context.h | 39 + content_handler/engine.cc | 258 +++++ content_handler/engine.h | 63 + content_handler/fuchsia_font_manager.cc | 47 +- content_handler/fuchsia_font_manager.h | 2 +- content_handler/isolate_configurator.cc | 114 ++ content_handler/isolate_configurator.h | 55 + content_handler/main.cc | 20 +- content_handler/platform_view.cc | 551 +++++++++ content_handler/platform_view.h | 120 ++ content_handler/rasterizer.cc | 19 - content_handler/rasterizer.h | 35 - content_handler/runtime_holder.cc | 911 --------------- content_handler/runtime_holder.h | 152 --- content_handler/service_protocol_hooks.cc | 164 --- content_handler/service_protocol_hooks.h | 37 - content_handler/session_connection.cc | 108 +- content_handler/session_connection.h | 52 +- content_handler/surface.cc | 73 ++ content_handler/surface.h | 47 + content_handler/task_observers.cc | 43 + content_handler/task_observers.h | 16 + content_handler/unique_fdio_ns.h | 34 + content_handler/vulkan_rasterizer.cc | 117 -- content_handler/vulkan_rasterizer.h | 42 - content_handler/vulkan_surface.cc | 24 +- content_handler/vulkan_surface.h | 11 +- content_handler/vulkan_surface_pool.cc | 7 +- content_handler/vulkan_surface_pool.h | 9 +- content_handler/vulkan_surface_producer.cc | 9 +- content_handler/vulkan_surface_producer.h | 18 +- flow/BUILD.gn | 10 +- flow/compositor_context.cc | 26 +- flow/compositor_context.h | 44 +- flow/debug_print.cc | 5 + flow/debug_print.h | 9 +- flow/export_node.cc | 15 +- flow/export_node.h | 5 +- flow/layers/default_layer_builder.cc | 6 +- flow/layers/default_layer_builder.h | 2 +- flow/layers/layer.h | 4 - flow/layers/layer_builder.h | 3 +- flow/layers/layer_tree.cc | 55 +- flow/layers/layer_tree.h | 21 - flow/layers/performance_overlay_layer.cc | 33 - flow/layers/performance_overlay_layer.h | 2 - flow/layers/picture_layer.cc | 23 +- flow/layers/picture_layer.h | 13 +- flow/process_info.h | 31 - flow/raster_cache.cc | 33 +- flow/raster_cache.h | 6 - flow/raster_cache_key.h | 30 +- flow/scene_update_context.cc | 17 +- flow/skia_gpu_object.cc | 44 + flow/skia_gpu_object.h | 88 ++ flow/texture.cc | 6 +- flow/texture.h | 5 +- fml/BUILD.gn | 18 +- fml/file.h | 35 + fml/icu_util.cc | 17 +- fml/macros.h | 20 + fml/mapping.cc | 20 + fml/mapping.h | 37 +- fml/memory/thread_checker.h | 69 ++ fml/memory/weak_ptr.h | 43 +- fml/message_loop.cc | 10 +- fml/message_loop.h | 9 +- fml/message_loop_impl.cc | 43 +- fml/message_loop_impl.h | 8 +- fml/message_loop_unittests.cc | 24 +- fml/native_library.h | 52 + fml/paths.cc | 31 + fml/paths.h | 4 + fml/platform/android/message_loop_android.h | 6 +- .../darwin/resource_mapping_darwin.mm | 4 +- fml/platform/fuchsia/paths_fuchsia.cc | 15 + fml/platform/linux/message_loop_linux.h | 6 +- fml/platform/posix/file_posix.cc | 71 ++ fml/platform/posix/mapping_posix.cc | 18 +- fml/platform/posix/native_library_posix.cc | 60 + fml/platform/win/file_win.cc | 119 ++ fml/platform/win/mapping_win.cc | 59 +- fml/platform/win/native_library_win.cc | 51 + fml/platform/win/wstring_conversion.h | 25 + fml/task_observer.h | 21 - fml/task_runner.cc | 12 + fml/task_runner.h | 7 +- fml/thread.cc | 9 +- fml/thread.h | 6 +- fml/unique_fd.cc | 35 + fml/unique_fd.h | 60 + fml/unique_object.h | 137 +++ lib/snapshot/BUILD.gn | 54 +- lib/ui/BUILD.gn | 11 +- lib/ui/compositing/scene_builder.cc | 9 +- lib/ui/compositing/scene_host.cc | 6 +- lib/ui/dart_runtime_hooks.cc | 62 +- lib/ui/painting/codec.cc | 114 +- lib/ui/painting/codec.h | 7 +- lib/ui/painting/gradient.cc | 12 +- lib/ui/painting/image.cc | 14 +- lib/ui/painting/image.h | 17 +- lib/ui/painting/image_encoding.cc | 23 +- lib/ui/painting/image_shader.cc | 11 +- lib/ui/painting/picture.cc | 25 +- lib/ui/painting/picture.h | 9 +- lib/ui/painting/picture_recorder.cc | 5 +- lib/ui/painting/resource_context.cc | 51 - lib/ui/painting/resource_context.h | 60 - lib/ui/painting/shader.cc | 12 +- lib/ui/painting/shader.h | 13 +- lib/ui/painting/utils.cc | 46 - lib/ui/painting/utils.h | 38 - lib/ui/text/font_collection.cc | 14 +- lib/ui/text/font_collection.h | 7 +- lib/ui/text/paragraph.cc | 5 +- lib/ui/text/paragraph.h | 5 + lib/ui/text/paragraph_builder.cc | 27 +- lib/ui/text/paragraph_builder.h | 11 +- lib/ui/text/paragraph_impl_blink.cc | 4 +- lib/ui/text/paragraph_impl_blink.h | 5 + lib/ui/text/paragraph_impl_txt.cc | 2 +- lib/ui/ui_dart_state.cc | 93 +- lib/ui/ui_dart_state.h | 101 +- .../window/platform_message_response_dart.cc | 14 +- .../window/platform_message_response_dart.h | 6 +- lib/ui/window/viewport_metrics.h | 19 + lib/ui/window/window.cc | 5 +- lib/ui/window/window.h | 5 +- runtime/BUILD.gn | 60 +- runtime/asset_font_selector.cc | 38 +- runtime/asset_font_selector.h | 17 +- runtime/dart_controller.cc | 250 ---- runtime/dart_controller.h | 55 - runtime/dart_init.cc | 725 ------------ runtime/dart_init.h | 64 - runtime/dart_isolate.cc | 715 ++++++++++++ runtime/dart_isolate.h | 152 +++ runtime/dart_isolate_unittests.cc | 103 ++ runtime/dart_service_isolate.h | 2 - runtime/dart_snapshot.cc | 159 +++ runtime/dart_snapshot.h | 57 + runtime/dart_snapshot_buffer.cc | 72 ++ runtime/dart_snapshot_buffer.h | 34 + runtime/dart_vm.cc | 472 ++++++++ runtime/dart_vm.h | 75 ++ runtime/dart_vm_unittests.cc | 21 + runtime/fixtures/simple_main.dart | 7 + runtime/runtime_controller.cc | 274 +++-- runtime/runtime_controller.h | 99 +- runtime/runtime_delegate.cc | 8 +- runtime/runtime_delegate.h | 8 +- runtime/runtime_init.cc | 35 - runtime/runtime_init.h | 21 - runtime/service_protocol.cc | 279 +++++ runtime/service_protocol.h | 99 ++ shell/common/BUILD.gn | 43 +- shell/common/animator.cc | 75 +- shell/common/animator.h | 37 +- shell/common/engine.cc | 583 +++------- shell/common/engine.h | 153 +-- shell/common/io_manager.cc | 73 ++ shell/common/io_manager.h | 52 + shell/common/isolate_configuration.cc | 144 +++ shell/common/isolate_configuration.h | 51 + shell/common/null_platform_view.cc | 37 - shell/common/null_platform_view.h | 39 - shell/common/null_rasterizer.cc | 67 -- shell/common/null_rasterizer.h | 51 - shell/common/platform_view.cc | 182 +-- shell/common/platform_view.h | 119 +- .../common/platform_view_service_protocol.cc | 447 ------- shell/common/platform_view_service_protocol.h | 85 -- shell/common/rasterizer.cc | 197 ++++ shell/common/rasterizer.h | 65 +- shell/common/run_configuration.cc | 80 ++ shell/common/run_configuration.h | 56 + shell/common/shell.cc | 1025 ++++++++++++----- shell/common/shell.h | 254 ++-- shell/common/shell_unittests.cc | 133 +++ shell/common/surface.cc | 28 +- shell/common/surface.h | 14 +- shell/common/switches.cc | 122 ++ shell/common/switches.h | 37 +- shell/common/thread_host.cc | 38 + shell/common/thread_host.h | 43 + shell/common/tracing_controller.cc | 51 - shell/common/tracing_controller.h | 34 - shell/common/vsync_waiter.cc | 37 + shell/common/vsync_waiter.h | 21 +- shell/common/vsync_waiter_fallback.cc | 24 +- shell/common/vsync_waiter_fallback.h | 13 +- shell/gpu/BUILD.gn | 11 +- shell/gpu/gpu_rasterizer.cc | 168 --- shell/gpu/gpu_rasterizer.h | 68 -- shell/gpu/gpu_surface_gl.cc | 13 +- shell/gpu/gpu_surface_gl.h | 5 +- shell/gpu/gpu_surface_software.cc | 17 +- shell/gpu/gpu_surface_software.h | 7 +- shell/gpu/gpu_surface_vulkan.h | 5 +- shell/platform/BUILD.gn | 6 +- shell/platform/android/BUILD.gn | 16 +- shell/platform/android/android_context_gl.cc | 24 +- shell/platform/android/android_context_gl.h | 1 - .../android/android_external_texture_gl.cc | 9 +- .../android/android_external_texture_gl.h | 3 +- .../platform/android/android_shell_holder.cc | 169 +++ shell/platform/android/android_shell_holder.h | 59 + shell/platform/android/android_surface.cc | 24 + shell/platform/android/android_surface.h | 7 +- shell/platform/android/android_surface_gl.cc | 37 +- shell/platform/android/android_surface_gl.h | 24 +- .../android/android_surface_software.cc | 14 +- .../android/android_surface_software.h | 26 +- .../android/android_surface_vulkan.cc | 15 +- .../platform/android/android_surface_vulkan.h | 13 +- shell/platform/android/apk_asset_provider.cc | 29 +- shell/platform/android/apk_asset_provider.h | 27 +- shell/platform/android/flutter_main.cc | 75 +- shell/platform/android/flutter_main.h | 27 +- shell/platform/android/library_loader.cc | 2 +- .../platform_message_response_android.cc | 62 + .../platform_message_response_android.h | 39 + .../platform/android/platform_view_android.cc | 589 ++-------- .../platform/android/platform_view_android.h | 98 +- .../android/platform_view_android_jni.cc | 416 +++++-- .../platform/android/vsync_waiter_android.cc | 100 +- shell/platform/android/vsync_waiter_android.h | 15 +- shell/platform/darwin/BUILD.gn | 12 +- shell/platform/darwin/common/BUILD.gn | 13 +- shell/platform/darwin/common/command_line.h | 17 + shell/platform/darwin/common/command_line.mm | 21 + shell/platform/darwin/common/platform_mac.h | 20 - shell/platform/darwin/common/platform_mac.mm | 160 --- .../darwin/common/process_info_mac.cc | 36 - .../platform/darwin/common/process_info_mac.h | 36 - shell/platform/darwin/desktop/BUILD.gn | 22 +- shell/platform/darwin/desktop/Info.plist | 8 +- .../darwin/desktop/flutter_app_delegate.h | 14 - .../darwin/desktop/flutter_app_delegate.m | 15 - .../darwin/desktop/flutter_application.mm | 8 - ...ation.h => flutter_application_delegate.h} | 11 +- .../desktop/flutter_application_delegate.mm | 80 ++ shell/platform/darwin/desktop/flutter_mac.xib | 695 ----------- .../platform/darwin/desktop/flutter_window.h | 6 +- .../platform/darwin/desktop/flutter_window.mm | 201 +++- shell/platform/darwin/desktop/main_mac.mm | 112 +- .../darwin/desktop/platform_view_mac.h | 27 +- .../darwin/desktop/platform_view_mac.mm | 107 +- .../darwin/desktop/vsync_waiter_mac.cc | 16 +- .../darwin/desktop/vsync_waiter_mac.h | 10 +- shell/platform/darwin/ios/BUILD.gn | 13 +- .../framework/Source/FlutterDartProject.mm | 397 +++---- .../Source/FlutterDartProject_Internal.h | 23 +- .../ios/framework/Source/FlutterDartSource.h | 30 - .../ios/framework/Source/FlutterDartSource.mm | 100 -- .../Source/FlutterHeadlessDartRunner.mm | 88 +- .../darwin/ios/framework/Source/FlutterView.h | 6 + .../ios/framework/Source/FlutterView.mm | 103 +- .../framework/Source/FlutterViewController.mm | 337 +++--- .../Source/FlutterViewController_Internal.h | 17 + .../framework/Source/accessibility_bridge.mm | 4 +- .../ios/framework/Source/flutter_main_ios.h | 18 - .../ios/framework/Source/flutter_main_ios.mm | 25 - .../Source/platform_message_response_darwin.h | 50 + .../platform_message_response_darwin.mm | 11 + .../Source/platform_message_router.h | 5 +- .../Source/platform_message_router.mm | 15 +- .../ios/framework/Source/vsync_waiter_ios.h | 19 +- .../ios/framework/Source/vsync_waiter_ios.mm | 115 +- .../darwin/ios/ios_external_texture_gl.h | 2 + .../darwin/ios/ios_external_texture_gl.mm | 19 +- shell/platform/darwin/ios/ios_gl_context.h | 2 +- shell/platform/darwin/ios/ios_gl_context.mm | 60 +- shell/platform/darwin/ios/ios_surface.h | 19 +- shell/platform/darwin/ios/ios_surface.mm | 31 +- shell/platform/darwin/ios/ios_surface_gl.h | 3 +- shell/platform/darwin/ios/ios_surface_gl.mm | 5 +- .../darwin/ios/ios_surface_software.h | 11 +- .../darwin/ios/ios_surface_software.mm | 9 +- shell/platform/darwin/ios/platform_view_ios.h | 93 +- .../platform/darwin/ios/platform_view_ios.mm | 143 +-- shell/platform/embedder/BUILD.gn | 8 +- shell/platform/embedder/embedder.cc | 245 ++-- shell/platform/embedder/embedder_engine.cc | 119 ++ shell/platform/embedder/embedder_engine.h | 53 + .../embedder/platform_view_embedder.cc | 53 +- .../embedder/platform_view_embedder.h | 29 +- shell/platform/linux/BUILD.gn | 23 - shell/platform/linux/main_linux.cc | 142 --- shell/platform/win/BUILD.gn | 30 - shell/platform/win/main_win.cc | 142 --- shell/testing/BUILD.gn | 26 +- shell/testing/platform_view_test.cc | 32 - shell/testing/platform_view_test.h | 38 - shell/testing/test_runner.cc | 48 - shell/testing/test_runner.h | 42 - shell/testing/tester_main.cc | 243 ++++ shell/testing/testing.cc | 24 - shell/testing/testing.h | 16 - sky/engine/platform/SharedBuffer.cpp | 1 - .../platform/fonts/FontFallbackList.cpp | 10 +- sky/engine/platform/fonts/FontFallbackList.h | 3 + sky/engine/web/Sky.cpp | 56 - synchronization/BUILD.gn | 5 +- synchronization/debug_thread_checker.h | 25 - synchronization/semaphore.cc | 6 +- testing/BUILD.gn | 4 + testing/thread_test.cc | 33 + testing/thread_test.h | 37 + tools/gn | 4 + travis/licenses_golden/licenses_flutter | 233 ++-- 345 files changed, 12543 insertions(+), 11072 deletions(-) create mode 100644 assets/asset_manager.cc create mode 100644 assets/asset_manager.h delete mode 100644 assets/asset_provider.h create mode 100644 assets/asset_resolver.h delete mode 100644 assets/unzipper_provider.cc delete mode 100644 assets/unzipper_provider.h create mode 100644 common/task_runners.cc create mode 100644 common/task_runners.h delete mode 100644 common/threads.cc delete mode 100644 common/threads.h create mode 100644 content_handler/README.md delete mode 100644 content_handler/app.cc delete mode 100644 content_handler/app.h create mode 100644 content_handler/application.cc create mode 100644 content_handler/application.h delete mode 100644 content_handler/application_controller_impl.cc delete mode 100644 content_handler/application_controller_impl.h create mode 100644 content_handler/application_runner.cc create mode 100644 content_handler/application_runner.h create mode 100644 content_handler/compositor_context.cc create mode 100644 content_handler/compositor_context.h create mode 100644 content_handler/engine.cc create mode 100644 content_handler/engine.h create mode 100644 content_handler/isolate_configurator.cc create mode 100644 content_handler/isolate_configurator.h create mode 100644 content_handler/platform_view.cc create mode 100644 content_handler/platform_view.h delete mode 100644 content_handler/rasterizer.cc delete mode 100644 content_handler/rasterizer.h delete mode 100644 content_handler/runtime_holder.cc delete mode 100644 content_handler/runtime_holder.h delete mode 100644 content_handler/service_protocol_hooks.cc delete mode 100644 content_handler/service_protocol_hooks.h create mode 100644 content_handler/surface.cc create mode 100644 content_handler/surface.h create mode 100644 content_handler/task_observers.cc create mode 100644 content_handler/task_observers.h create mode 100644 content_handler/unique_fdio_ns.h delete mode 100644 content_handler/vulkan_rasterizer.cc delete mode 100644 content_handler/vulkan_rasterizer.h delete mode 100644 flow/process_info.h create mode 100644 flow/skia_gpu_object.cc create mode 100644 flow/skia_gpu_object.h create mode 100644 fml/file.h create mode 100644 fml/macros.h create mode 100644 fml/mapping.cc create mode 100644 fml/memory/thread_checker.h create mode 100644 fml/native_library.h create mode 100644 fml/paths.cc create mode 100644 fml/platform/fuchsia/paths_fuchsia.cc create mode 100644 fml/platform/posix/file_posix.cc create mode 100644 fml/platform/posix/native_library_posix.cc create mode 100644 fml/platform/win/file_win.cc create mode 100644 fml/platform/win/native_library_win.cc create mode 100644 fml/platform/win/wstring_conversion.h delete mode 100644 fml/task_observer.h create mode 100644 fml/unique_fd.cc create mode 100644 fml/unique_fd.h create mode 100644 fml/unique_object.h delete mode 100644 lib/ui/painting/resource_context.cc delete mode 100644 lib/ui/painting/resource_context.h delete mode 100644 lib/ui/painting/utils.cc delete mode 100644 lib/ui/painting/utils.h delete mode 100644 runtime/dart_controller.cc delete mode 100644 runtime/dart_controller.h delete mode 100644 runtime/dart_init.cc delete mode 100644 runtime/dart_init.h create mode 100644 runtime/dart_isolate.cc create mode 100644 runtime/dart_isolate.h create mode 100644 runtime/dart_isolate_unittests.cc create mode 100644 runtime/dart_snapshot.cc create mode 100644 runtime/dart_snapshot.h create mode 100644 runtime/dart_snapshot_buffer.cc create mode 100644 runtime/dart_snapshot_buffer.h create mode 100644 runtime/dart_vm.cc create mode 100644 runtime/dart_vm.h create mode 100644 runtime/dart_vm_unittests.cc create mode 100644 runtime/fixtures/simple_main.dart delete mode 100644 runtime/runtime_init.cc delete mode 100644 runtime/runtime_init.h create mode 100644 runtime/service_protocol.cc create mode 100644 runtime/service_protocol.h create mode 100644 shell/common/io_manager.cc create mode 100644 shell/common/io_manager.h create mode 100644 shell/common/isolate_configuration.cc create mode 100644 shell/common/isolate_configuration.h delete mode 100644 shell/common/null_platform_view.cc delete mode 100644 shell/common/null_platform_view.h delete mode 100644 shell/common/null_rasterizer.cc delete mode 100644 shell/common/null_rasterizer.h delete mode 100644 shell/common/platform_view_service_protocol.cc delete mode 100644 shell/common/platform_view_service_protocol.h create mode 100644 shell/common/run_configuration.cc create mode 100644 shell/common/run_configuration.h create mode 100644 shell/common/shell_unittests.cc create mode 100644 shell/common/thread_host.cc create mode 100644 shell/common/thread_host.h delete mode 100644 shell/common/tracing_controller.cc delete mode 100644 shell/common/tracing_controller.h delete mode 100644 shell/gpu/gpu_rasterizer.cc delete mode 100644 shell/gpu/gpu_rasterizer.h create mode 100644 shell/platform/android/android_shell_holder.cc create mode 100644 shell/platform/android/android_shell_holder.h create mode 100644 shell/platform/android/platform_message_response_android.cc create mode 100644 shell/platform/android/platform_message_response_android.h create mode 100644 shell/platform/darwin/common/command_line.h create mode 100644 shell/platform/darwin/common/command_line.mm delete mode 100644 shell/platform/darwin/common/platform_mac.h delete mode 100644 shell/platform/darwin/common/platform_mac.mm delete mode 100644 shell/platform/darwin/common/process_info_mac.cc delete mode 100644 shell/platform/darwin/common/process_info_mac.h delete mode 100644 shell/platform/darwin/desktop/flutter_app_delegate.h delete mode 100644 shell/platform/darwin/desktop/flutter_app_delegate.m delete mode 100644 shell/platform/darwin/desktop/flutter_application.mm rename shell/platform/darwin/desktop/{flutter_application.h => flutter_application_delegate.h} (65%) create mode 100644 shell/platform/darwin/desktop/flutter_application_delegate.mm delete mode 100644 shell/platform/darwin/desktop/flutter_mac.xib delete mode 100644 shell/platform/darwin/ios/framework/Source/FlutterDartSource.h delete mode 100644 shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm create mode 100644 shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h delete mode 100644 shell/platform/darwin/ios/framework/Source/flutter_main_ios.h delete mode 100644 shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm create mode 100644 shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h create mode 100644 shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm create mode 100644 shell/platform/embedder/embedder_engine.cc create mode 100644 shell/platform/embedder/embedder_engine.h delete mode 100644 shell/platform/linux/BUILD.gn delete mode 100644 shell/platform/linux/main_linux.cc delete mode 100644 shell/platform/win/BUILD.gn delete mode 100644 shell/platform/win/main_win.cc delete mode 100644 shell/testing/platform_view_test.cc delete mode 100644 shell/testing/platform_view_test.h delete mode 100644 shell/testing/test_runner.cc delete mode 100644 shell/testing/test_runner.h create mode 100644 shell/testing/tester_main.cc delete mode 100644 shell/testing/testing.cc delete mode 100644 shell/testing/testing.h delete mode 100644 synchronization/debug_thread_checker.h create mode 100644 testing/thread_test.cc create mode 100644 testing/thread_test.h diff --git a/BUILD.gn b/BUILD.gn index 24dda026c6245..b37b0b8d4054c 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -10,14 +10,12 @@ group("flutter") { public_deps = [ "$flutter_root/lib/snapshot:generate_snapshot_bin", "$flutter_root/lib/snapshot:kernel_platform_files", + "$flutter_root/shell/testing", "$flutter_root/sky", - "$flutter_root/third_party/txt", ] if (flutter_runtime_mode != "debug") { - public_deps += [ - "$flutter_root/lib/snapshot:entry_points_json_files", - ] + public_deps += [ "$flutter_root/lib/snapshot:entry_points_json_files" ] } if (!is_fuchsia && !is_fuchsia_host) { @@ -45,20 +43,24 @@ group("flutter") { "$flutter_root/shell/platform/embedder:flutter_embedder_framework", ] } - if (!is_win) { - public_deps += [ - "$flutter_root/shell/platform/embedder:embedder_unittests", - "$flutter_root/shell/platform/embedder:flutter_engine", - ] - } + public_deps += [ "$flutter_root/flow:flow_unittests", "$flutter_root/fml:fml_unittests", + "$flutter_root/runtime:runtime_unittests", + "$flutter_root/shell/common:shell_unittests", "$flutter_root/sky/engine/wtf:wtf_unittests", "$flutter_root/synchronization:synchronization_unittests", "$flutter_root/third_party/txt:txt_unittests", "//garnet/public/lib/fxl:fxl_unittests", ] + + if (!is_win) { + public_deps += [ + "$flutter_root/shell/platform/embedder:embedder_unittests", + "$flutter_root/shell/platform/embedder:flutter_engine", + ] + } } } @@ -74,29 +76,23 @@ if (is_fuchsia) { "$flutter_root/content_handler:aot", ] if (flutter_runtime_mode != "release") { - deps += [ - "//third_party/dart/runtime/observatory:embedded_archive_observatory", - ] + deps += [ "//third_party/dart/runtime/observatory:embedded_archive_observatory" ] } binary = "flutter_aot_runner" if (flutter_runtime_mode != "release") { - resources = [ - { - path = rebase_path( - "$root_gen_dir/observatory/embedded_archive_observatory.tar") - dest = "observatory.tar" - }, - ] + resources = [ { + path = rebase_path( + "$root_gen_dir/observatory/embedded_archive_observatory.tar") + dest = "observatory.tar" + } ] } - meta = [ - { - path = rebase_path("content_handler/meta/sandbox") - dest = "sandbox" - }, - ] + meta = [ { + path = rebase_path("content_handler/meta/sandbox") + dest = "sandbox" + } ] } package("flutter_jit_runner") { @@ -104,29 +100,23 @@ if (is_fuchsia) { "$flutter_root/content_handler:jit", ] if (flutter_runtime_mode != "release") { - deps += [ - "//third_party/dart/runtime/observatory:embedded_archive_observatory", - ] + deps += [ "//third_party/dart/runtime/observatory:embedded_archive_observatory" ] } binary = "flutter_jit_runner" if (flutter_runtime_mode != "release") { - resources = [ - { - path = rebase_path( - "$root_gen_dir/observatory/embedded_archive_observatory.tar") - dest = "observatory.tar" - }, - ] + resources = [ { + path = rebase_path( + "$root_gen_dir/observatory/embedded_archive_observatory.tar") + dest = "observatory.tar" + } ] } - meta = [ - { - path = rebase_path("content_handler/meta/sandbox") - dest = "sandbox" - }, - ] + meta = [ { + path = rebase_path("content_handler/meta/sandbox") + dest = "sandbox" + } ] } } else { group("dist") { diff --git a/DEPS b/DEPS index aa3dc7026f0e5..2c6cab9ff5532 100644 --- a/DEPS +++ b/DEPS @@ -115,7 +115,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '8dddd90bf943a8174913564353b30a3b11ee0f7a', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '3cf97e01cdbd4bb920fa3d40282a56c4b2d62a58', # Fuchsia compatibility # diff --git a/assets/BUILD.gn b/assets/BUILD.gn index c4901375ad810..28d7e569659f1 100644 --- a/assets/BUILD.gn +++ b/assets/BUILD.gn @@ -4,16 +4,18 @@ source_set("assets") { sources = [ - "asset_provider.h", + "asset_manager.cc", + "asset_manager.h", + "asset_resolver.h", "directory_asset_bundle.cc", "directory_asset_bundle.h", - "unzipper_provider.cc", - "unzipper_provider.h", "zip_asset_store.cc", "zip_asset_store.h", ] deps = [ + "$flutter_root/common", + "$flutter_root/fml", "$flutter_root/glue", "//garnet/public/lib/fxl", "//garnet/public/lib/zip", @@ -23,7 +25,5 @@ source_set("assets") { "//third_party/zlib:minizip", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] } diff --git a/assets/asset_manager.cc b/assets/asset_manager.cc new file mode 100644 index 0000000000000..8a313f0729c96 --- /dev/null +++ b/assets/asset_manager.cc @@ -0,0 +1,55 @@ +// 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/assets/asset_manager.h" + +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/assets/zip_asset_store.h" +#include "flutter/glue/trace_event.h" +#include "lib/fxl/files/path.h" + +namespace blink { + +AssetManager::AssetManager() = default; + +AssetManager::~AssetManager() = default; + +void AssetManager::PushFront(std::unique_ptr resolver) { + if (resolver == nullptr || !resolver->IsValid()) { + return; + } + + resolvers_.push_front(std::move(resolver)); +} + +void AssetManager::PushBack(std::unique_ptr resolver) { + if (resolver == nullptr || !resolver->IsValid()) { + return; + } + + resolvers_.push_back(std::move(resolver)); +} + +// |blink::AssetResolver| +bool AssetManager::GetAsBuffer(const std::string& asset_name, + std::vector* data) const { + if (asset_name.size() == 0) { + return false; + } + TRACE_EVENT0("flutter", "AssetManager::GetAsBuffer"); + for (const auto& resolver : resolvers_) { + if (resolver->GetAsBuffer(asset_name, data)) { + return true; + } + } + FXL_DLOG(ERROR) << "Could not find asset: " << asset_name; + return false; +} + +// |blink::AssetResolver| +bool AssetManager::IsValid() const { + return resolvers_.size() > 0; +} + +} // namespace blink diff --git a/assets/asset_manager.h b/assets/asset_manager.h new file mode 100644 index 0000000000000..fc7f3ef05210e --- /dev/null +++ b/assets/asset_manager.h @@ -0,0 +1,47 @@ +// 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_ASSETS_ASSET_MANAGER_H_ +#define FLUTTER_ASSETS_ASSET_MANAGER_H_ + +#include +#include +#include + +#include "flutter/assets/asset_resolver.h" +#include "lib/fxl/files/unique_fd.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/ref_counted.h" + +namespace blink { + +class AssetManager final : public AssetResolver, + public fxl::RefCountedThreadSafe { + public: + void PushFront(std::unique_ptr resolver); + + void PushBack(std::unique_ptr resolver); + + // |blink::AssetResolver| + bool IsValid() const override; + + // |blink::AssetResolver| + bool GetAsBuffer(const std::string& asset_name, + std::vector* data) const override; + + private: + std::deque> resolvers_; + + AssetManager(); + + ~AssetManager(); + + FXL_DISALLOW_COPY_AND_ASSIGN(AssetManager); + FRIEND_MAKE_REF_COUNTED(AssetManager); + FRIEND_REF_COUNTED_THREAD_SAFE(AssetManager); +}; + +} // namespace blink + +#endif // FLUTTER_ASSETS_ASSET_MANAGER_H_ diff --git a/assets/asset_provider.h b/assets/asset_provider.h deleted file mode 100644 index 68b7f5c2b7b9c..0000000000000 --- a/assets/asset_provider.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 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_ASSETS_ASSET_PROVIDER_H_ -#define FLUTTER_ASSETS_ASSET_PROVIDER_H_ - -#include -#include - -#include "lib/fxl/memory/ref_counted.h" - -namespace blink { - -class AssetProvider - : public fxl::RefCountedThreadSafe - { - public: - virtual bool GetAsBuffer(const std::string& asset_name, - std::vector* data) = 0; - virtual ~AssetProvider() = default; -}; - -} // namespace blink -#endif // FLUTTER_ASSETS_ASSET_PROVIDER_H diff --git a/assets/asset_resolver.h b/assets/asset_resolver.h new file mode 100644 index 0000000000000..6cfe27961a9f4 --- /dev/null +++ b/assets/asset_resolver.h @@ -0,0 +1,32 @@ +// 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_ASSETS_ASSET_RESOLVER_H_ +#define FLUTTER_ASSETS_ASSET_RESOLVER_H_ + +#include +#include + +#include "lib/fxl/macros.h" + +namespace blink { + +class AssetResolver { + public: + AssetResolver() = default; + + virtual ~AssetResolver() = default; + + virtual bool IsValid() const = 0; + + virtual bool GetAsBuffer(const std::string& asset_name, + std::vector* data) const = 0; + + private: + FXL_DISALLOW_COPY_AND_ASSIGN(AssetResolver); +}; + +} // namespace blink + +#endif // FLUTTER_ASSETS_ASSET_RESOLVER_H_ diff --git a/assets/directory_asset_bundle.cc b/assets/directory_asset_bundle.cc index 43933079a81bd..8e5d4df2ab977 100644 --- a/assets/directory_asset_bundle.cc +++ b/assets/directory_asset_bundle.cc @@ -3,73 +3,54 @@ // found in the LICENSE file. #include "flutter/assets/directory_asset_bundle.h" -#include "lib/fxl/build_config.h" - -#include #include +#include "flutter/fml/file.h" +#include "flutter/fml/mapping.h" #include "lib/fxl/files/eintr_wrapper.h" -#include "lib/fxl/files/file.h" -#include "lib/fxl/files/path.h" -#include "lib/fxl/files/unique_fd.h" -#include "lib/fxl/portable_unistd.h" namespace blink { -bool DirectoryAssetBundle::GetAsBuffer(const std::string& asset_name, - std::vector* data) { - if (fd_.is_valid()) { -#if defined(OS_WIN) - // This code path is not valid in a Windows environment. - return false; -#else - fxl::UniqueFD asset_file(openat(fd_.get(), asset_name.c_str(), O_RDONLY)); - if (!asset_file.is_valid()) - return false; - - constexpr size_t kBufferSize = 1 << 16; - size_t offset = 0; - ssize_t bytes_read = 0; - do { - offset += bytes_read; - data->resize(offset + kBufferSize); - bytes_read = read(asset_file.get(), &(*data)[offset], kBufferSize); - } while (bytes_read > 0); +DirectoryAssetBundle::DirectoryAssetBundle(fml::UniqueFD descriptor) + : descriptor_(std::move(descriptor)) { + if (!fml::IsDirectory(descriptor_)) { + return; + } + is_valid_ = true; +} - if (bytes_read < 0) { - FXL_LOG(ERROR) << "Reading " << asset_name << " failed"; - data->clear(); - return false; - } +DirectoryAssetBundle::~DirectoryAssetBundle() = default; - data->resize(offset + bytes_read); - return true; -#endif - } - std::string asset_path = GetPathForAsset(asset_name); - if (asset_path.empty()) - return false; - return files::ReadFileToVector(asset_path, data); +// |blink::AssetResolver| +bool DirectoryAssetBundle::IsValid() const { + return is_valid_; } -DirectoryAssetBundle::~DirectoryAssetBundle() {} +// |blink::AssetResolver| +bool DirectoryAssetBundle::GetAsBuffer(const std::string& asset_name, + std::vector* data) const { + if (data == nullptr) { + return false; + } -DirectoryAssetBundle::DirectoryAssetBundle(std::string directory) - : directory_(std::move(directory)), fd_() {} + if (!is_valid_) { + FXL_DLOG(WARNING) << "Asset bundle was not valid."; + return false; + } -DirectoryAssetBundle::DirectoryAssetBundle(fxl::UniqueFD fd) - : fd_(std::move(fd)) {} + fml::FileMapping mapping( + fml::OpenFile(descriptor_, asset_name.c_str(), fml::OpenPermission::kRead, + false /* directory */), + false /* executable */); -std::string DirectoryAssetBundle::GetPathForAsset( - const std::string& asset_name) { - std::string asset_path = files::SimplifyPath(directory_ + "/" + asset_name); - if (asset_path.find(directory_) != 0u) { - FXL_LOG(ERROR) << "Asset name '" << asset_name - << "' attempted to traverse outside asset bundle."; - return std::string(); + if (mapping.GetMapping() == nullptr) { + return false; } - return asset_path; + + data->resize(mapping.GetSize()); + memmove(data->data(), mapping.GetMapping(), mapping.GetSize()); + return true; } } // namespace blink diff --git a/assets/directory_asset_bundle.h b/assets/directory_asset_bundle.h index c710a513796ae..b594e1357fbe2 100644 --- a/assets/directory_asset_bundle.h +++ b/assets/directory_asset_bundle.h @@ -5,31 +5,31 @@ #ifndef FLUTTER_ASSETS_DIRECTORY_ASSET_BUNDLE_H_ #define FLUTTER_ASSETS_DIRECTORY_ASSET_BUNDLE_H_ -#include -#include - -#include "flutter/assets/asset_provider.h" -#include "lib/fxl/files/unique_fd.h" +#include "flutter/assets/asset_resolver.h" +#include "flutter/fml/unique_fd.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_counted.h" namespace blink { -class DirectoryAssetBundle - : public AssetProvider { +class DirectoryAssetBundle : public AssetResolver { public: - explicit DirectoryAssetBundle(std::string directory); - // Expects fd to be valid, otherwise the file descriptor is ignored. - explicit DirectoryAssetBundle(fxl::UniqueFD fd); - virtual ~DirectoryAssetBundle(); - - virtual bool GetAsBuffer(const std::string& asset_name, std::vector* data); + explicit DirectoryAssetBundle(fml::UniqueFD descriptor); - std::string GetPathForAsset(const std::string& asset_name); + ~DirectoryAssetBundle() override; private: - const std::string directory_; - fxl::UniqueFD fd_; + const fml::UniqueFD descriptor_; + bool is_valid_ = false; + + std::string GetPathForAsset(const std::string& asset_name) const; + + // |blink::AssetResolver| + bool IsValid() const override; + + // |blink::AssetResolver| + bool GetAsBuffer(const std::string& asset_name, + std::vector* data) const override; FXL_DISALLOW_COPY_AND_ASSIGN(DirectoryAssetBundle); }; diff --git a/assets/unzipper_provider.cc b/assets/unzipper_provider.cc deleted file mode 100644 index 8ed023f9a20e9..0000000000000 --- a/assets/unzipper_provider.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/assets/unzipper_provider.h" - -#include "lib/fxl/logging.h" -#include "third_party/zlib/contrib/minizip/unzip.h" - -namespace blink { - -UnzipperProvider GetUnzipperProviderForPath(std::string zip_path) { - return [zip_path]() { - zip::UniqueUnzipper unzipper(unzOpen2(zip_path.c_str(), nullptr)); - if (!unzipper.is_valid()) - FXL_LOG(ERROR) << "Unable to open zip file: " << zip_path; - return unzipper; - }; -} - -} // namespace blink diff --git a/assets/unzipper_provider.h b/assets/unzipper_provider.h deleted file mode 100644 index f0f8d9597dffd..0000000000000 --- a/assets/unzipper_provider.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2016 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_ASSETS_UNZIP_PROVIDER_H_ -#define FLUTTER_ASSETS_UNZIP_PROVIDER_H_ - -#include - -#include "lib/zip/unique_unzipper.h" - -namespace blink { - -using UnzipperProvider = std::function; - -UnzipperProvider GetUnzipperProviderForPath(std::string zip_path); - -} // namespace blink - -#endif // FLUTTER_ASSETS_UNZIP_PROVIDER_H_ diff --git a/assets/zip_asset_store.cc b/assets/zip_asset_store.cc index c8534fa10c216..1b9216bd34530 100644 --- a/assets/zip_asset_store.cc +++ b/assets/zip_asset_store.cc @@ -15,21 +15,28 @@ #include #include "flutter/glue/trace_event.h" -#include "lib/fxl/files/eintr_wrapper.h" -#include "lib/fxl/files/unique_fd.h" -#include "lib/zip/unique_unzipper.h" namespace blink { -ZipAssetStore::ZipAssetStore(UnzipperProvider unzipper_provider) - : unzipper_provider_(std::move(unzipper_provider)) { +ZipAssetStore::ZipAssetStore(std::string file_path) + : file_path_(std::move(file_path)) { BuildStatCache(); } ZipAssetStore::~ZipAssetStore() = default; +zip::UniqueUnzipper ZipAssetStore::CreateUnzipper() const { + return zip::UniqueUnzipper{::unzOpen2(file_path_.c_str(), nullptr)}; +} + +// |blink::AssetResolver| +bool ZipAssetStore::IsValid() const { + return stat_cache_.size() > 0; +} + +// |blink::AssetResolver| bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, - std::vector* data) { + std::vector* data) const { TRACE_EVENT0("flutter", "ZipAssetStore::GetAsBuffer"); auto found = stat_cache_.find(asset_name); @@ -37,7 +44,7 @@ bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, return false; } - auto unzipper = unzipper_provider_(); + auto unzipper = CreateUnzipper(); if (!unzipper.is_valid()) { return false; @@ -73,7 +80,8 @@ bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, void ZipAssetStore::BuildStatCache() { TRACE_EVENT0("flutter", "ZipAssetStore::BuildStatCache"); - auto unzipper = unzipper_provider_(); + + auto unzipper = CreateUnzipper(); if (!unzipper.is_valid()) { return; diff --git a/assets/zip_asset_store.h b/assets/zip_asset_store.h index 1ffda483ba9b7..558678e25bc08 100644 --- a/assets/zip_asset_store.h +++ b/assets/zip_asset_store.h @@ -6,21 +6,20 @@ #define FLUTTER_ASSETS_ZIP_ASSET_STORE_H_ #include -#include -#include "flutter/assets/unzipper_provider.h" +#include "flutter/assets/asset_resolver.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_counted.h" +#include "lib/zip/unique_unzipper.h" #include "third_party/zlib/contrib/minizip/unzip.h" namespace blink { -class ZipAssetStore : public fxl::RefCountedThreadSafe { +class ZipAssetStore final : public AssetResolver { public: - explicit ZipAssetStore(UnzipperProvider unzipper_provider); - ~ZipAssetStore(); + ZipAssetStore(std::string file_path); - bool GetAsBuffer(const std::string& asset_name, std::vector* data); + ~ZipAssetStore() override; private: struct CacheEntry { @@ -30,11 +29,20 @@ class ZipAssetStore : public fxl::RefCountedThreadSafe { : file_pos(p_file_pos), uncompressed_size(p_uncompressed_size) {} }; - UnzipperProvider unzipper_provider_; - std::map stat_cache_; + std::string file_path_; + mutable std::map stat_cache_; + + // |blink::AssetResolver| + bool IsValid() const override; + + // |blink::AssetResolver| + bool GetAsBuffer(const std::string& asset_name, + std::vector* data) const override; void BuildStatCache(); + zip::UniqueUnzipper CreateUnzipper() const; + FXL_DISALLOW_COPY_AND_ASSIGN(ZipAssetStore); }; diff --git a/common/BUILD.gn b/common/BUILD.gn index 53b71914d49d1..47cd7d3d62644 100644 --- a/common/BUILD.gn +++ b/common/BUILD.gn @@ -12,11 +12,12 @@ source_set("common") { sources = [ "settings.cc", "settings.h", - "threads.cc", - "threads.h", + "task_runners.cc", + "task_runners.h", ] deps = [ + "$flutter_root/fml", "//garnet/public/lib/fxl", ] diff --git a/common/settings.cc b/common/settings.cc index 0198f714cbaad..85523e1b9a29f 100644 --- a/common/settings.cc +++ b/common/settings.cc @@ -4,26 +4,50 @@ #include "flutter/common/settings.h" -#include - -#include "lib/fxl/logging.h" +#include namespace blink { -namespace { - -Settings* g_settings = nullptr; - -} // namespace - -const Settings& Settings::Get() { - FXL_CHECK(g_settings); - return *g_settings; -} -void Settings::Set(const Settings& settings) { - FXL_CHECK(!g_settings); - g_settings = new Settings(); - *g_settings = settings; +std::string Settings::ToString() const { + std::stringstream stream; + stream << "Settings: " << std::endl; + stream << "aot_snapshot_path: " << aot_snapshot_path << std::endl; + stream << "script_snapshot_path: " << script_snapshot_path << std::endl; + stream << "aot_vm_snapshot_data_filename: " << aot_vm_snapshot_data_filename + << std::endl; + stream << "aot_vm_snapshot_instr_filename: " << aot_vm_snapshot_instr_filename + << std::endl; + stream << "aot_isolate_snapshot_data_filename: " + << aot_isolate_snapshot_data_filename << std::endl; + stream << "aot_isolate_snapshot_instr_filename: " + << aot_isolate_snapshot_instr_filename << std::endl; + stream << "application_library_path: " << application_library_path + << std::endl; + stream << "main_dart_file_path: " << main_dart_file_path << std::endl; + stream << "packages_file_path: " << packages_file_path << std::endl; + stream << "temp_directory_path: " << temp_directory_path << std::endl; + stream << "dart_flags:" << std::endl; + for (const auto& dart_flag : dart_flags) { + stream << " " << dart_flag << std::endl; + } + stream << "start_paused: " << start_paused << std::endl; + stream << "trace_skia: " << trace_skia << std::endl; + stream << "trace_startup: " << trace_startup << std::endl; + stream << "endless_trace_buffer: " << endless_trace_buffer << std::endl; + stream << "enable_dart_profiling: " << enable_dart_profiling << std::endl; + stream << "dart_non_checked_mode: " << dart_non_checked_mode << std::endl; + stream << "enable_observatory: " << enable_observatory << std::endl; + stream << "observatory_port: " << observatory_port << std::endl; + stream << "ipv6: " << ipv6 << std::endl; + stream << "use_test_fonts: " << use_test_fonts << std::endl; + stream << "enable_software_rendering: " << enable_software_rendering + << std::endl; + stream << "using_blink: " << using_blink << std::endl; + stream << "log_tag: " << log_tag << std::endl; + stream << "icu_data_path: " << icu_data_path << std::endl; + stream << "assets_dir: " << assets_dir << std::endl; + stream << "assets_path: " << assets_path << std::endl; + return stream.str(); } } // namespace blink diff --git a/common/settings.h b/common/settings.h index 5bb5c6cbbea42..c6c3159766a37 100644 --- a/common/settings.h +++ b/common/settings.h @@ -5,40 +5,82 @@ #ifndef FLUTTER_COMMON_SETTINGS_H_ #define FLUTTER_COMMON_SETTINGS_H_ +#include #include +#include #include #include +#include "flutter/fml/unique_fd.h" +#include "lib/fxl/functional/closure.h" + namespace blink { +using TaskObserverAdd = + std::function; +using TaskObserverRemove = std::function; + struct Settings { - bool enable_observatory = false; - // Port on target will be auto selected by the OS. A message will be printed - // on the target with the port after it has been selected. - uint32_t observatory_port = 0; - bool ipv6 = false; - bool start_paused = false; - bool trace_startup = false; - bool endless_trace_buffer = false; - bool enable_dart_profiling = false; - bool use_test_fonts = false; - bool dart_non_checked_mode = false; - bool enable_software_rendering = false; - bool using_blink = true; - std::string aot_shared_library_path; + // VM settings + std::string script_snapshot_path; + std::string kernel_snapshot_path; + std::string aot_snapshot_path; std::string aot_vm_snapshot_data_filename; std::string aot_vm_snapshot_instr_filename; std::string aot_isolate_snapshot_data_filename; std::string aot_isolate_snapshot_instr_filename; + std::string application_library_path; + std::string application_kernel_asset; + + std::string main_dart_file_path; + std::string packages_file_path; + std::string temp_directory_path; std::vector dart_flags; + + // Isolate settings + bool start_paused = false; + bool trace_skia = false; + bool trace_startup = false; + bool endless_trace_buffer = false; + bool enable_dart_profiling = false; + bool dart_non_checked_mode = false; + + // Observatory settings + bool enable_observatory = false; + // Port on target will be auto selected by the OS. A message will be printed + // on the target with the port after it has been selected. + uint32_t observatory_port = 0; + bool ipv6 = false; + + // Font settings + bool use_test_fonts = false; + + // Engine settings + TaskObserverAdd task_observer_add; + TaskObserverRemove task_observer_remove; + // The main isolate is current when this callback is made. This is a good spot + // to perform native Dart bindings for libraries not built in. + fxl::Closure root_isolate_create_callback; + // The isolate is not current and may have already been destroyed when this + // call is made. + fxl::Closure root_isolate_shutdown_callback; + bool enable_software_rendering = false; + bool using_blink = false; + bool skia_deterministic_rendering_on_cpu = false; std::string log_tag = "flutter"; + std::string icu_data_path; + + // Assets settings + fml::UniqueFD::element_type assets_dir = + fml::UniqueFD::traits_type::InvalidValue(); + std::string assets_path; + std::string flx_path; - static const Settings& Get(); - static void Set(const Settings& settings); + std::string ToString() const; }; } // namespace blink diff --git a/common/task_runners.cc b/common/task_runners.cc new file mode 100644 index 0000000000000..1a09daec1815c --- /dev/null +++ b/common/task_runners.cc @@ -0,0 +1,48 @@ +// 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/common/task_runners.h" + +#include + +namespace blink { + +TaskRunners::TaskRunners(std::string label, + fxl::RefPtr platform, + fxl::RefPtr gpu, + fxl::RefPtr ui, + fxl::RefPtr io) + : label_(std::move(label)), + platform_(std::move(platform)), + gpu_(std::move(gpu)), + ui_(std::move(ui)), + io_(std::move(io)) {} + +TaskRunners::~TaskRunners() = default; + +const std::string& TaskRunners::GetLabel() const { + return label_; +} + +fxl::RefPtr TaskRunners::GetPlatformTaskRunner() const { + return platform_; +} + +fxl::RefPtr TaskRunners::GetUITaskRunner() const { + return ui_; +} + +fxl::RefPtr TaskRunners::GetIOTaskRunner() const { + return io_; +} + +fxl::RefPtr TaskRunners::GetGPUTaskRunner() const { + return gpu_; +} + +bool TaskRunners::IsValid() const { + return platform_ && gpu_ && ui_ && io_; +} + +} // namespace blink diff --git a/common/task_runners.h b/common/task_runners.h new file mode 100644 index 0000000000000..f41ae147ebad0 --- /dev/null +++ b/common/task_runners.h @@ -0,0 +1,46 @@ +// 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_COMMON_TASK_RUNNERS_H_ +#define FLUTTER_COMMON_TASK_RUNNERS_H_ + +#include + +#include "lib/fxl/macros.h" +#include "lib/fxl/tasks/task_runner.h" + +namespace blink { + +class TaskRunners { + public: + TaskRunners(std::string label, + fxl::RefPtr platform, + fxl::RefPtr gpu, + fxl::RefPtr ui, + fxl::RefPtr io); + + ~TaskRunners(); + + const std::string& GetLabel() const; + + fxl::RefPtr GetPlatformTaskRunner() const; + + fxl::RefPtr GetUITaskRunner() const; + + fxl::RefPtr GetIOTaskRunner() const; + + fxl::RefPtr GetGPUTaskRunner() const; + + bool IsValid() const; + + private: + const std::string label_; + fxl::RefPtr platform_; + fxl::RefPtr gpu_; + fxl::RefPtr ui_; + fxl::RefPtr io_; +}; +} // namespace blink + +#endif // FLUTTER_COMMON_TASK_RUNNERS_H_ diff --git a/common/threads.cc b/common/threads.cc deleted file mode 100644 index 3634d8d7c8723..0000000000000 --- a/common/threads.cc +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/common/threads.h" - -#include - -namespace blink { -namespace { - -Threads* g_threads = nullptr; - -} // namespace - -Threads::Threads() {} - -Threads::Threads(fxl::RefPtr platform, - fxl::RefPtr gpu, - fxl::RefPtr ui, - fxl::RefPtr io) - : platform_(std::move(platform)), - gpu_(std::move(gpu)), - ui_(std::move(ui)), - io_(std::move(io)) {} - -Threads::~Threads() {} - -const fxl::RefPtr& Threads::Platform() { - return Get().platform_; -} - -const fxl::RefPtr& Threads::Gpu() { - return Get().gpu_; -} - -const fxl::RefPtr& Threads::UI() { - return Get().ui_; -} - -const fxl::RefPtr& Threads::IO() { - return Get().io_; -} - -const Threads& Threads::Get() { - FXL_CHECK(g_threads); - return *g_threads; -} - -void Threads::Set(const Threads& threads) { - FXL_CHECK(!g_threads); - g_threads = new Threads(); - *g_threads = threads; -} - -} // namespace blink diff --git a/common/threads.h b/common/threads.h deleted file mode 100644 index 456a5eba8ad97..0000000000000 --- a/common/threads.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 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_COMMON_THREADS_H_ -#define FLUTTER_COMMON_THREADS_H_ - -#include "lib/fxl/tasks/task_runner.h" - -#define ASSERT_IS_PLATFORM_THREAD \ - FXL_DCHECK(::blink::Threads::Platform()->RunsTasksOnCurrentThread()); -#define ASSERT_IS_GPU_THREAD \ - FXL_DCHECK(::blink::Threads::Gpu()->RunsTasksOnCurrentThread()); -#define ASSERT_IS_UI_THREAD \ - FXL_DCHECK(::blink::Threads::UI()->RunsTasksOnCurrentThread()); -#define ASSERT_IS_IO_THREAD \ - FXL_DCHECK(::blink::Threads::IO()->RunsTasksOnCurrentThread()); - -namespace blink { - -class Threads { - public: - Threads(); - Threads(fxl::RefPtr platform, - fxl::RefPtr gpu, - fxl::RefPtr ui, - fxl::RefPtr io); - ~Threads(); - - static const fxl::RefPtr& Platform(); - static const fxl::RefPtr& Gpu(); - static const fxl::RefPtr& UI(); - static const fxl::RefPtr& IO(); - - static void Set(const Threads& settings); - - private: - static const Threads& Get(); - - fxl::RefPtr platform_; - fxl::RefPtr gpu_; - fxl::RefPtr ui_; - fxl::RefPtr io_; -}; - -} // namespace blink - -#endif // FLUTTER_COMMON_THREADS_H_ diff --git a/content_handler/BUILD.gn b/content_handler/BUILD.gn index 6bc00b4e2786c..4778784baa643 100644 --- a/content_handler/BUILD.gn +++ b/content_handler/BUILD.gn @@ -20,23 +20,28 @@ template("flutter_content_handler") { sources = [ "accessibility_bridge.cc", "accessibility_bridge.h", - "app.cc", - "app.h", - "application_controller_impl.cc", - "application_controller_impl.h", + "application.cc", + "application.h", + "application_runner.cc", + "application_runner.h", + "compositor_context.cc", + "compositor_context.h", + "engine.cc", + "engine.h", "fuchsia_font_manager.cc", "fuchsia_font_manager.h", + "isolate_configurator.cc", + "isolate_configurator.h", "main.cc", - "rasterizer.cc", - "rasterizer.h", - "runtime_holder.cc", - "runtime_holder.h", - "service_protocol_hooks.cc", - "service_protocol_hooks.h", + "platform_view.cc", + "platform_view.h", "session_connection.cc", "session_connection.h", - "vulkan_rasterizer.cc", - "vulkan_rasterizer.h", + "surface.cc", + "surface.h", + "task_observers.cc", + "task_observers.h", + "unique_fdio_ns.h", "vulkan_surface.cc", "vulkan_surface.h", "vulkan_surface_pool.cc", @@ -45,18 +50,26 @@ template("flutter_content_handler") { "vulkan_surface_producer.h", ] + # The use of these dependencies is temporary and will be moved behind the + # embedder API. + flutter_deps = [ + "$flutter_root/assets", + "$flutter_root/common", + "$flutter_root/flow", + "$flutter_root/glue", + "$flutter_root/lib/ui", + "$flutter_root/runtime", + "$flutter_root/sky/engine/platform", + "$flutter_root/third_party/txt", + "$flutter_root/vulkan", + "$flutter_root/fml", + "$flutter_root/shell/common", + "$flutter_root/shell/gpu", + ] + deps = [ "//third_party/dart/runtime/bin:libdart_builtin", "//third_party/dart/runtime/platform:libdart_platform", - "$flutter_root/assets", - "$flutter_root/common", - "$flutter_root/flow", - "$flutter_root/glue", - "$flutter_root/lib/ui", - "$flutter_root/runtime", - "$flutter_root/sky/engine/platform", - "$flutter_root/third_party/txt", - "$flutter_root/vulkan", "//garnet/public/lib/app/cpp", "//garnet/public/lib/fsl", "//garnet/public/lib/fxl", @@ -73,8 +86,10 @@ template("flutter_content_handler") { "//topaz/lib/tonic", "//topaz/public/dart-pkg/fuchsia", "//topaz/public/lib/ui/flutter/sdk_ext", + "//third_party/skia:gpu", + "//third_party/zlib:minizip", "//zircon/public/lib/trace-provider", - ] + extra_deps + ] + extra_deps + flutter_deps # The flags below are needed so that Dart's CPU profiler can walk the # C++ stack. diff --git a/content_handler/README.md b/content_handler/README.md new file mode 100644 index 0000000000000..4461e808d1a47 --- /dev/null +++ b/content_handler/README.md @@ -0,0 +1,4 @@ +Flutter Application Runner +========================== + +Implements the `component::ApplicationRunner` FIDL interface to launch and run mutliple Flutter applications within the same process. diff --git a/content_handler/accessibility_bridge.cc b/content_handler/accessibility_bridge.cc index cb6f9b8e21155..f3d52f6cdbbb6 100644 --- a/content_handler/accessibility_bridge.cc +++ b/content_handler/accessibility_bridge.cc @@ -2,21 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/content_handler/accessibility_bridge.h" +#include "accessibility_bridge.h" #include -#include "flutter/lib/ui/semantics/semantics_node.h" #include "lib/app/cpp/application_context.h" -#include "lib/fxl/macros.h" +#include "lib/context/fidl/context_writer.fidl.h" #include "third_party/rapidjson/rapidjson/document.h" #include "third_party/rapidjson/rapidjson/stringbuffer.h" #include "third_party/rapidjson/rapidjson/writer.h" -namespace flutter_runner { +namespace flutter { -AccessibilityBridge::AccessibilityBridge(component::ApplicationContext* context) - : writer_(context->ConnectToEnvironmentService()) {} +AccessibilityBridge::AccessibilityBridge(maxwell::ContextWriterPtr writer) + : writer_(std::move(writer)) {} + +AccessibilityBridge::~AccessibilityBridge() = default; void AccessibilityBridge::UpdateSemantics( const blink::SemanticsNodeUpdates& update) { @@ -77,4 +78,4 @@ void AccessibilityBridge::EraseUnvisitedNodes( } } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/accessibility_bridge.h b/content_handler/accessibility_bridge.h index 7ac54e754d9b6..dde8bfaa54c36 100644 --- a/content_handler/accessibility_bridge.h +++ b/content_handler/accessibility_bridge.h @@ -2,28 +2,32 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ -#define FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ +#pragma once #include #include "flutter/lib/ui/semantics/semantics_node.h" -#include "lib/app/cpp/application_context.h" -#include +#include "lib/context/fidl/context_writer.fidl.h" +#include "lib/fxl/macros.h" -namespace flutter_runner { +namespace flutter { // Maintain an up-to-date list of SemanticsNodes on screen, and communicate // with the Context Service. -class AccessibilityBridge { +class AccessibilityBridge final { public: - explicit AccessibilityBridge(component::ApplicationContext* context); + AccessibilityBridge(maxwell::ContextWriterPtr writer); + + ~AccessibilityBridge(); // Update the internal representation of the semantics nodes, and write the // semantics to Context Service. void UpdateSemantics(const blink::SemanticsNodeUpdates& update); private: + maxwell::ContextWriterPtr writer_; + std::map semantics_nodes_; + // Walk the semantics node tree starting at |id|, and store the id of each // visited child in |visited_nodes|. void UpdateVisitedForNodeAndChildren(const int id, @@ -33,10 +37,7 @@ class AccessibilityBridge { // |visited_nodes|. void EraseUnvisitedNodes(const std::vector& visited_nodes); - std::map semantics_nodes_; - modular::ContextWriterPtr writer_; + FXL_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge); }; -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ +} // namespace flutter diff --git a/content_handler/app.cc b/content_handler/app.cc deleted file mode 100644 index 1f1bde833d2f3..0000000000000 --- a/content_handler/app.cc +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/content_handler/app.h" - -#include -#include - -#include "flutter/common/settings.h" -#include "flutter/common/threads.h" -#include "flutter/content_handler/fuchsia_font_manager.h" -#include "flutter/lib/ui/text/font_collection.h" -#include "flutter/sky/engine/platform/fonts/fuchsia/FontCacheFuchsia.h" -#include "lib/fsl/tasks/message_loop.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/tasks/task_runner.h" -#include "lib/icu_data/cpp/icu_data.h" -#include "third_party/dart/runtime/include/dart_tools_api.h" - -namespace flutter_runner { -namespace { - -static App* g_app = nullptr; - -void QuitMessageLoop() { - fsl::MessageLoop::GetCurrent()->QuitNow(); -} - -std::string GetLabelFromURL(const std::string& url) { - size_t last_slash = url.rfind('/'); - if (last_slash == std::string::npos || last_slash + 1 == url.length()) - return url; - return url.substr(last_slash + 1); -} - -} // namespace - -App::App() { - g_app = this; - context_ = component::ApplicationContext::CreateFromStartupInfo(); - - gpu_thread_ = std::make_unique(); - io_thread_ = std::make_unique(); - - auto gpu_thread_success = gpu_thread_->Run(); - auto io_thread_success = io_thread_->Run(); - - FXL_CHECK(gpu_thread_success) << "Must be able to create the GPU thread"; - FXL_CHECK(io_thread_success) << "Must be able to create the IO thread"; - - auto ui_task_runner = fsl::MessageLoop::GetCurrent()->task_runner(); - auto gpu_task_runner = gpu_thread_->TaskRunner(); - auto io_task_runner = io_thread_->TaskRunner(); - - // Notice that the Platform and UI threads are actually the same. - blink::Threads::Set(blink::Threads(ui_task_runner, // Platform - gpu_task_runner, // GPU - ui_task_runner, // UI - io_task_runner // IO - )); - - if (!icu_data::Initialize(context_.get())) { - FXL_LOG(ERROR) << "Could not initialize ICU data."; - } - - blink::Settings settings; - settings.enable_observatory = true; - blink::Settings::Set(settings); - - fonts::FontProviderPtr font_provider( - context_->ConnectToEnvironmentService()); - if (settings.using_blink) { - blink::SetFontProvider(std::move(font_provider)); - } else { - blink::FontCollection::ForProcess().GetFontCollection()-> - SetAssetFontManager( - sk_make_sp(std::move(font_provider))); - } - - context_->outgoing_services()->AddService( - [this](fidl::InterfaceRequest request) { - runner_bindings_.AddBinding(this, std::move(request)); - }); -} - -App::~App() { - icu_data::Release(); - blink::Threads::Gpu()->PostTask(QuitMessageLoop); - blink::Threads::IO()->PostTask(QuitMessageLoop); - g_app = nullptr; -} - -App& App::Shared() { - FXL_DCHECK(g_app); - return *g_app; -} - -void App::WaitForPlatformViewIds( - std::vector* platform_view_ids) { - fxl::AutoResetWaitableEvent latch; - - blink::Threads::UI()->PostTask([this, platform_view_ids, &latch]() { - WaitForPlatformViewsIdsUIThread(platform_view_ids, &latch); - }); - - latch.Wait(); -} - -void App::WaitForPlatformViewsIdsUIThread( - std::vector* platform_view_ids, - fxl::AutoResetWaitableEvent* latch) { - for (auto it = controllers_.begin(); it != controllers_.end(); it++) { - ApplicationControllerImpl* controller = it->first; - - if (!controller) { - continue; - } - - PlatformViewInfo info; - // TODO(zra): We should create real IDs for these instead of relying on the - // address of the controller. Maybe just use the UI Isolate main port? - info.view_id = reinterpret_cast(controller); - info.isolate_id = controller->GetUIIsolateMainPort(); - info.isolate_name = controller->GetUIIsolateName(); - platform_view_ids->push_back(info); - } - latch->Signal(); -} - -void App::StartApplication( - component::ApplicationPackage application, - component::ApplicationStartupInfo startup_info, - fidl::InterfaceRequest controller) { - if (controllers_.empty()) { - // Name this process after the url of the first application being launched. - base_label_ = "flutter:" + GetLabelFromURL(startup_info.launch_info.url); - } - - std::unique_ptr impl = - std::make_unique(this, std::move(application), - std::move(startup_info), - std::move(controller)); - ApplicationControllerImpl* key = impl.get(); - controllers_.emplace(key, std::move(impl)); - - UpdateProcessLabel(); -} - -void App::Destroy(ApplicationControllerImpl* controller) { - auto it = controllers_.find(controller); - if (it == controllers_.end()) - return; - controllers_.erase(it); - UpdateProcessLabel(); -} - -void App::UpdateProcessLabel() { - std::string label; - if (controllers_.size() < 2) { - label = base_label_; - } else { - std::string suffix = " (+" + std::to_string(controllers_.size() - 1) + ")"; - if (base_label_.size() + suffix.size() <= ZX_MAX_NAME_LEN - 1) { - label = base_label_ + suffix; - } else { - label = base_label_.substr(0, ZX_MAX_NAME_LEN - 1 - suffix.size() - 3) + - "..." + suffix; - } - } - zx::process::self().set_property(ZX_PROP_NAME, label.c_str(), label.size()); -} - -} // namespace flutter_runner diff --git a/content_handler/app.h b/content_handler/app.h deleted file mode 100644 index dc8c49927d897..0000000000000 --- a/content_handler/app.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2016 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_CONTENT_HANDLER_APP_H_ -#define FLUTTER_CONTENT_HANDLER_APP_H_ - -#include -#include - -#include "flutter/content_handler/application_controller_impl.h" -#include "lib/app/cpp/application_context.h" -#include -#include "lib/fsl/threading/thread.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/synchronization/waitable_event.h" - -namespace flutter_runner { - -class App : public component::ApplicationRunner { - public: - App(); - ~App(); - - static App& Shared(); - - // |component::ApplicationRunner| implementation: - - void StartApplication( - component::ApplicationPackage application, - component::ApplicationStartupInfo startup_info, - fidl::InterfaceRequest controller) override; - - void Destroy(ApplicationControllerImpl* controller); - - struct PlatformViewInfo { - uintptr_t view_id; - int64_t isolate_id; - std::string isolate_name; - }; - - void WaitForPlatformViewIds(std::vector* platform_view_ids); - - private: - void WaitForPlatformViewsIdsUIThread( - std::vector* platform_view_ids, - fxl::AutoResetWaitableEvent* latch); - void UpdateProcessLabel(); - - std::unique_ptr context_; - std::unique_ptr gpu_thread_; - std::unique_ptr io_thread_; - fidl::BindingSet runner_bindings_; - std::unordered_map> - controllers_; - std::string base_label_; - - FXL_DISALLOW_COPY_AND_ASSIGN(App); -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_APP_H_ diff --git a/content_handler/application.cc b/content_handler/application.cc new file mode 100644 index 0000000000000..7dd2270d42317 --- /dev/null +++ b/content_handler/application.cc @@ -0,0 +1,313 @@ +// Copyright 2018 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. + +#include "application.h" + +#include +#include + +#include + +#include "flutter/shell/common/switches.h" +#include "lib/fsl/vmo/file.h" +#include "lib/fsl/vmo/vector.h" +#include "lib/fxl/command_line.h" +#include "lib/fxl/synchronization/waitable_event.h" +#include "task_observers.h" + +namespace flutter { + +std::pair, std::unique_ptr> +Application::Create( + Application::Delegate& delegate, + component::ApplicationPackagePtr package, + component::ApplicationStartupInfoPtr startup_info, + f1dl::InterfaceRequest controller) { + auto thread = std::make_unique(); + std::unique_ptr application; + + fxl::AutoResetWaitableEvent latch; + thread->TaskRunner()->PostTask([&]() mutable { + application.reset(new Application(delegate, // + std::move(package), // + std::move(startup_info), // + std::move(controller) // + )); + latch.Signal(); + }); + thread->Run(); + latch.Wait(); + return {std::move(thread), std::move(application)}; +} + +static std::string DebugLabelForURL(const std::string url) { + auto found = url.rfind("/"); + if (found == std::string::npos) { + return url; + } else { + return {url, found + 1}; + } +} + +Application::Application( + Application::Delegate& delegate, + component::ApplicationPackagePtr package, + component::ApplicationStartupInfoPtr startup_info, + f1dl::InterfaceRequest + application_controller_request) + : delegate_(delegate), + debug_label_(DebugLabelForURL(startup_info->launch_info->url)), + application_controller_(this) { + application_controller_.set_error_handler([this]() { Kill(); }); + + FXL_DCHECK(fdio_ns_.is_valid()); + // ApplicationLaunchInfo::url non-optional. + auto& launch_info = startup_info->launch_info; + + // ApplicationLaunchInfo::arguments optional. + if (auto& arguments = launch_info->arguments) { + settings_ = shell::SettingsFromCommandLine( + fxl::CommandLineFromIterators(arguments->begin(), arguments->end())); + } + + // TODO: ApplicationLaunchInfo::out optional. + + // TODO: ApplicationLaunchInfo::err optional. + + // ApplicationLaunchInfo::service_request optional. + if (launch_info->directory_request) { + service_provider_bridge_.ServeDirectory( + std::move(launch_info->directory_request)); + } + + // ApplicationLaunchInfo::flat_namespace optional. + if (auto& flat_namespace = startup_info->flat_namespace) { + for (size_t i = 0; i < flat_namespace->paths->size(); ++i) { + const auto& path = flat_namespace->paths->at(i); + if (path == "/svc") { + continue; + } + + zx::channel dir = std::move(flat_namespace->directories->at(i)); + zx_handle_t dir_handle = dir.release(); + if (fdio_ns_bind(fdio_ns_.get(), path->data(), dir_handle) != ZX_OK) { + FXL_DLOG(ERROR) << "Could not bind path to namespace: " << path; + zx_handle_close(dir_handle); + } + } + } else { + FXL_DLOG(ERROR) << "There was no flat namespace."; + } + + application_directory_.reset(fdio_ns_opendir(fdio_ns_.get())); + FXL_DCHECK(application_directory_.is_valid()); + + application_assets_directory_.reset( + openat(application_directory_.get(), "pkg/data", O_RDONLY | O_DIRECTORY)); + + // TODO: ApplicationLaunchInfo::additional_services optional. + + // ApplicationPackage::data: This is legacy FLX data. Ensure that we dont have + // any. + FXL_DCHECK(!package->data) << "Legacy FLX data must not be supplied."; + + // All launch arguments have been read. Perform service binding and + // final settings configuration. The next call will be to create a view + // for this application. + + service_provider_bridge_.AddService( + std::bind(&Application::CreateShellForView, this, std::placeholders::_1)); + + component::ServiceProviderPtr outgoing_services; + outgoing_services_request_ = outgoing_services.NewRequest(); + service_provider_bridge_.set_backend(std::move(outgoing_services)); + + // Setup the application controller binding. + if (application_controller_request) { + application_controller_.Bind(std::move(application_controller_request)); + } + + application_context_ = + component::ApplicationContext::CreateFrom(std::move(startup_info)); + + settings_.enable_observatory = true; + + settings_.icu_data_path = ""; + + settings_.using_blink = false; + + settings_.assets_dir = application_assets_directory_.get(); + + settings_.script_snapshot_path = "snapshot_blob.bin"; + + settings_.log_tag = debug_label_ + std::string{"(flutter)"}; + +#ifndef NDEBUG + // Debug mode + settings_.dart_non_checked_mode = false; +#else // NDEBUG + // Release mode + settings_.dart_non_checked_mode = true; +#endif // NDEBUG + + settings_.task_observer_add = + std::bind(&CurrentMessageLoopAddAfterTaskObserver, std::placeholders::_1, + std::placeholders::_2); + + settings_.task_observer_remove = std::bind( + &CurrentMessageLoopRemoveAfterTaskObserver, std::placeholders::_1); + + AttemptVMLaunchWithCurrentSettings(settings_); +} + +Application::~Application() = default; + +void Application::AttemptVMLaunchWithCurrentSettings( + const blink::Settings& settings) const { + if (blink::DartVM::ForProcessIfInitialized()) { + return; + } + + if (!blink::DartVM::IsRunningPrecompiledCode()) { + // We will be initializing the VM lazily in this case. + return; + } + + fsl::SizedVmo dylib_vmo; + + if (!fsl::VmoFromFilenameAt( + application_assets_directory_.get() /* /pkg/data */, "libapp.so", + &dylib_vmo)) { + FXL_LOG(ERROR) << "Dylib containing VM and isolate snapshots does not " + "exist. Will not be able to launch VM."; + return; + } + + dlerror(); + + auto library_handle = dlopen_vmo(dylib_vmo.vmo().get(), RTLD_LAZY); + + if (library_handle == nullptr) { + FXL_LOG(ERROR) << "Could not open dylib: " << dlerror(); + return; + } + + auto lib = fxl::MakeRefCounted( + library_handle, // library handle + true // close the handle when done + ); + + auto symbol = [](const char* str) { + return std::string{"_"} + std::string{str}; + }; + + fxl::RefPtr vm_snapshot = + fxl::MakeRefCounted( + blink::DartSnapshotBuffer::CreateWithSymbolInLibrary( + lib, symbol(blink::DartSnapshot::kVMDataSymbol).c_str()), + blink::DartSnapshotBuffer::CreateWithSymbolInLibrary( + lib, symbol(blink::DartSnapshot::kVMInstructionsSymbol).c_str())); + + fxl::RefPtr isolate_snapshot = + fxl::MakeRefCounted( + blink::DartSnapshotBuffer::CreateWithSymbolInLibrary( + lib, symbol(blink::DartSnapshot::kIsolateDataSymbol).c_str()), + blink::DartSnapshotBuffer::CreateWithSymbolInLibrary( + lib, + symbol(blink::DartSnapshot::kIsolateInstructionsSymbol).c_str())); + + blink::DartVM::ForProcess(settings_, // + std::move(vm_snapshot), // + std::move(isolate_snapshot) // + ); + if (blink::DartVM::ForProcessIfInitialized()) { + FXL_DLOG(INFO) << "VM successfully initialized for AOT mode."; + } else { + FXL_LOG(ERROR) << "VM could not be initialized for AOT mode."; + } +} + +// |component::ApplicationController| +void Application::Kill() { + if (last_return_code_.first) { + for (auto wait_callback : wait_callbacks_) { + wait_callback(last_return_code_.second); + } + } + wait_callbacks_.clear(); + + delegate_.OnApplicationTerminate(this); + // WARNING: Don't do anything past this point as this instance may have been + // collected. +} + +// |component::ApplicationController| +void Application::Detach() { + application_controller_.set_error_handler(nullptr); +} + +// |component::ApplicationController| +void Application::Wait(const WaitCallback& callback) { + wait_callbacks_.emplace_back(std::move(callback)); +} + +// |flutter::Engine::Delegate| +void Application::OnEngineTerminate(const Engine* shell_holder) { + auto found = std::find_if(shell_holders_.begin(), shell_holders_.end(), + [shell_holder](const auto& holder) { + return holder.get() == shell_holder; + }); + + if (found == shell_holders_.end()) { + return; + } + + // We may launch multiple shell in this application. However, we will + // terminate when the last shell goes away. The error code return to the + // application controller will be the last isolate that had an error. + auto return_code = shell_holder->GetEngineReturnCode(); + if (return_code.first) { + last_return_code_ = return_code; + } + + shell_holders_.erase(found); + + if (shell_holders_.size() == 0) { + Kill(); + // WARNING: Don't do anything past this point because the delegate may have + // collected this instance via the termination callback. + } +} + +void Application::CreateShellForView( + f1dl::InterfaceRequest view_provider_request) { + shells_bindings_.AddBinding(this, std::move(view_provider_request)); +} + +// |mozart::ViewProvider| +void Application::CreateView( + f1dl::InterfaceRequest view_owner, + f1dl::InterfaceRequest) { + if (!application_context_) { + FXL_DLOG(ERROR) << "Application context was invalid when attempting to " + "create a shell for a view provider request."; + return; + } + + // This method may be called multiple times. Care must be taken to ensure that + // all arguments can be accessed or synthesized multiple times. + // TODO(chinmaygarde): Figure out how to re-create the outgoing service + // request handle. + shell_holders_.emplace(std::make_unique( + *this, // delegate + debug_label_, // thread label + *application_context_, // application context + settings_, // settings + std::move(view_owner), // view owner + fdio_ns_, // FDIO namespace + std::move(outgoing_services_request_) // outgoing request + )); +} + +} // namespace flutter diff --git a/content_handler/application.h b/content_handler/application.h new file mode 100644 index 0000000000000..e4f5da105cac8 --- /dev/null +++ b/content_handler/application.h @@ -0,0 +1,97 @@ +// Copyright 2018 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. + +#pragma once + +#include +#include +#include + +#include "engine.h" +#include "flutter/common/settings.h" +#include "lib/app/cpp/application_context.h" +#include "lib/app/fidl/application_controller.fidl.h" +#include "lib/fidl/cpp/bindings/binding_set.h" +#include "lib/fsl/threading/thread.h" +#include "lib/fxl/files/unique_fd.h" +#include "lib/fxl/macros.h" +#include "lib/svc/cpp/service_provider_bridge.h" +#include "lib/ui/views/fidl/view_provider.fidl.h" +#include "unique_fdio_ns.h" + +namespace flutter { + +// Represents an instance of a Flutter application that contains one of more +// Flutter engine instances. +class Application final : public Engine::Delegate, + public component::ApplicationController, + public mozart::ViewProvider { + public: + class Delegate { + public: + virtual void OnApplicationTerminate(const Application* application) = 0; + }; + + // Creates a dedicated thread to run the application and constructions the + // application on it. The application can be accessed only on this thread. + // This is a synchronous operation. + static std::pair, std::unique_ptr> + Create(Application::Delegate& delegate, + component::ApplicationPackagePtr package, + component::ApplicationStartupInfoPtr startup_info, + f1dl::InterfaceRequest controller); + + // Must be called on the same thread returned from the create call. The thread + // may be collected after. + ~Application(); + + private: + blink::Settings settings_; + Delegate& delegate_; + const std::string debug_label_; + UniqueFDIONS fdio_ns_ = UniqueFDIONSCreate(); + fxl::UniqueFD application_directory_; + fxl::UniqueFD application_assets_directory_; + f1dl::Binding application_controller_; + f1dl::InterfaceRequest outgoing_services_request_; + component::ServiceProviderBridge service_provider_bridge_; + std::unique_ptr application_context_; + f1dl::BindingSet shells_bindings_; + std::set> shell_holders_; + std::vector wait_callbacks_; + std::pair last_return_code_; + + Application( + Application::Delegate& delegate, + component::ApplicationPackagePtr package, + component::ApplicationStartupInfoPtr startup_info, + f1dl::InterfaceRequest controller); + + // |component::ApplicationController| + void Kill() override; + + // |component::ApplicationController| + void Detach() override; + + // |component::ApplicationController| + void Wait(const WaitCallback& callback) override; + + // |mozart::ViewProvider| + void CreateView( + f1dl::InterfaceRequest view_owner, + f1dl::InterfaceRequest services) override; + + // |flutter::Engine::Delegate| + void OnEngineTerminate(const Engine* holder) override; + + void CreateShellForView( + f1dl::InterfaceRequest view_provider_request); + + void AttemptVMLaunchWithCurrentSettings( + const blink::Settings& settings) const; + + FXL_DISALLOW_COPY_AND_ASSIGN(Application); +}; + +} // namespace flutter diff --git a/content_handler/application_controller_impl.cc b/content_handler/application_controller_impl.cc deleted file mode 100644 index 9a1b449138a1b..0000000000000 --- a/content_handler/application_controller_impl.cc +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/content_handler/application_controller_impl.h" - -#include - -#include -#include - -#include "flutter/content_handler/app.h" -#include "flutter/content_handler/runtime_holder.h" -#include "lib/app/cpp/connect.h" -#include "lib/fsl/vmo/vector.h" -#include "lib/fxl/logging.h" - -namespace flutter_runner { - -ApplicationControllerImpl::ApplicationControllerImpl( - App* app, - component::ApplicationPackage application, - component::ApplicationStartupInfo startup_info, - fidl::InterfaceRequest controller) - : app_(app), binding_(this) { - if (controller.is_valid()) { - binding_.Bind(std::move(controller)); - binding_.set_error_handler([this] { - app_->Destroy(this); - // |this| has been deleted at this point. - }); - } - - std::vector bundle; - if (application.data) { - if (!fsl::VectorFromVmo(std::move(*application.data), &bundle)) { - FXL_LOG(ERROR) << "Failed to receive bundle."; - return; - } - } - - // TODO(jeffbrown): Decide what to do with command-line arguments and - // startup handles. - - if (startup_info.launch_info.directory_request.is_valid()) { - service_provider_bridge_.ServeDirectory( - std::move(startup_info.launch_info.directory_request)); - } - - service_provider_bridge_.AddService( - [this](fidl::InterfaceRequest request) { - view_provider_bindings_.AddBinding(this, std::move(request)); - }); - - component::ServiceProviderPtr service_provider; - auto request = service_provider.NewRequest(); - service_provider_bridge_.set_backend(std::move(service_provider)); - - fdio_ns_t* fdio_ns = SetupNamespace(&startup_info.flat_namespace); - if (fdio_ns == nullptr) { - FXL_LOG(ERROR) << "Failed to initialize namespace"; - return; - } - - url_ = startup_info.launch_info.url; - runtime_holder_.reset(new RuntimeHolder()); - runtime_holder_->SetMainIsolateShutdownCallback([this]() { Kill(); }); - runtime_holder_->Init( - fdio_ns, - component::ApplicationContext::CreateFrom(std::move(startup_info)), - std::move(request), std::move(bundle)); -} - -ApplicationControllerImpl::~ApplicationControllerImpl() = default; - -constexpr char kServiceRootPath[] = "/svc"; - -fdio_ns_t* ApplicationControllerImpl::SetupNamespace( - component::FlatNamespace* flat) { - fdio_ns_t* fdio_namespc; - zx_status_t status = fdio_ns_create(&fdio_namespc); - if (status != ZX_OK) { - FXL_LOG(ERROR) << "Failed to create namespace"; - return nullptr; - } - for (size_t i = 0; i < flat->paths->size(); ++i) { - if (flat->paths->at(i) == kServiceRootPath) { - // Ownership of /svc goes to the ApplicationContext created above. - continue; - } - zx::channel dir = std::move(flat->directories->at(i)); - zx_handle_t dir_handle = dir.release(); - const char* path = flat->paths->at(i)->data(); - status = fdio_ns_bind(fdio_namespc, path, dir_handle); - if (status != ZX_OK) { - FXL_LOG(ERROR) << "Failed to bind " << flat->paths->at(i) - << " to namespace"; - zx_handle_close(dir_handle); - fdio_ns_destroy(fdio_namespc); - return nullptr; - } - } - return fdio_namespc; -} - -void ApplicationControllerImpl::Kill() { - SendReturnCode(runtime_holder_->return_code()); - runtime_holder_.reset(); - app_->Destroy(this); - // |this| has been deleted at this point. -} - -void ApplicationControllerImpl::Detach() { - binding_.set_error_handler(fxl::Closure()); -} - -void ApplicationControllerImpl::Wait(WaitCallback callback) { - wait_callbacks_.push_back(std::move(callback)); -} - -void ApplicationControllerImpl::SendReturnCode(int32_t return_code) { - for (const auto& iter : wait_callbacks_) { - iter(return_code); - } - wait_callbacks_.clear(); -} - -void ApplicationControllerImpl::CreateView( - fidl::InterfaceRequest view_owner_request, - fidl::InterfaceRequest services) { - runtime_holder_->CreateView(url_, std::move(view_owner_request), - std::move(services)); -} - -Dart_Port ApplicationControllerImpl::GetUIIsolateMainPort() { - if (!runtime_holder_) - return ILLEGAL_PORT; - return runtime_holder_->GetUIIsolateMainPort(); -} - -std::string ApplicationControllerImpl::GetUIIsolateName() { - if (!runtime_holder_) { - return ""; - } - return runtime_holder_->GetUIIsolateName(); -} - -} // namespace flutter_runner diff --git a/content_handler/application_controller_impl.h b/content_handler/application_controller_impl.h deleted file mode 100644 index 01700f2886ffb..0000000000000 --- a/content_handler/application_controller_impl.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2016 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_CONTENT_HANDLER_APPLICATION_IMPL_H_ -#define FLUTTER_CONTENT_HANDLER_APPLICATION_IMPL_H_ - -#include - -#include - -#include -#include -#include - -#include "lib/fidl/cpp/binding.h" -#include "lib/fidl/cpp/binding_set.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/synchronization/waitable_event.h" -#include "lib/svc/cpp/service_provider_bridge.h" -#include "third_party/dart/runtime/include/dart_api.h" - -namespace flutter_runner { -class App; -class RuntimeHolder; - -class ApplicationControllerImpl : public component::ApplicationController, - public views_v1::ViewProvider { - public: - ApplicationControllerImpl( - App* app, - component::ApplicationPackage application, - component::ApplicationStartupInfo startup_info, - fidl::InterfaceRequest controller); - - ~ApplicationControllerImpl() override; - - // |component::ApplicationController| implementation - - void Kill() override; - void Detach() override; - void Wait(WaitCallback callback) override; - - // |views_v1::ViewProvider| implementation - - void CreateView( - fidl::InterfaceRequest view_owner_request, - fidl::InterfaceRequest services) override; - - Dart_Port GetUIIsolateMainPort(); - std::string GetUIIsolateName(); - - private: - void StartRuntimeIfReady(); - void SendReturnCode(int32_t return_code); - - fdio_ns_t* SetupNamespace(component::FlatNamespace* flat); - - App* app_; - fidl::Binding binding_; - - component::ServiceProviderBridge service_provider_bridge_; - - fidl::BindingSet view_provider_bindings_; - - std::string url_; - std::unique_ptr runtime_holder_; - - std::vector wait_callbacks_; - - FXL_DISALLOW_COPY_AND_ASSIGN(ApplicationControllerImpl); -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_APPLICATION_IMPL_H_ diff --git a/content_handler/application_runner.cc b/content_handler/application_runner.cc new file mode 100644 index 0000000000000..2d77f43cbdd45 --- /dev/null +++ b/content_handler/application_runner.cc @@ -0,0 +1,90 @@ +// Copyright 2018 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. + +#include "application_runner.h" + +#include + +#include "flutter/lib/ui/text/font_collection.h" +#include "fuchsia_font_manager.h" +#include "lib/fonts/fidl/font_provider.fidl.h" +#include "lib/icu_data/cpp/icu_data.h" + +namespace flutter { + +ApplicationRunner::ApplicationRunner(fxl::Closure on_termination_callback) + : on_termination_callback_(std::move(on_termination_callback)), + host_context_(component::ApplicationContext::CreateFromStartupInfo()) { + SetupICU(); + + SetupGlobalFonts(); + + const std::string process_label = "flutter"; + zx::process::self().set_property(ZX_PROP_NAME, process_label.c_str(), + process_label.size()); + + host_context_->outgoing_services()->AddService( + std::bind(&ApplicationRunner::RegisterApplication, this, + std::placeholders::_1)); + + active_applications_bindings_.set_empty_set_handler( + [this]() { FireTerminationCallbackIfNecessary(); }); +} + +ApplicationRunner::~ApplicationRunner() { + host_context_->outgoing_services() + ->RemoveService(); +} + +void ApplicationRunner::RegisterApplication( + f1dl::InterfaceRequest request) { + active_applications_bindings_.AddBinding(this, std::move(request)); +} + +void ApplicationRunner::StartApplication( + component::ApplicationPackagePtr package, + component::ApplicationStartupInfoPtr startup_info, + f1dl::InterfaceRequest controller) { + auto thread_application_pair = + Application::Create(*this, // delegate + std::move(package), // application pacakge + std::move(startup_info), // startup info + std::move(controller) // controller request + ); + active_applications_[thread_application_pair.second.get()] = + std::move(thread_application_pair); +} + +void ApplicationRunner::OnApplicationTerminate(const Application* application) { + active_applications_.erase(application); + FireTerminationCallbackIfNecessary(); +} + +void ApplicationRunner::SetupICU() { + if (!icu_data::Initialize(host_context_.get())) { + FXL_LOG(ERROR) << "Could not initialize ICU data."; + } +} + +void ApplicationRunner::SetupGlobalFonts() { + fonts::FontProviderPtr font_provider( + host_context_->ConnectToEnvironmentService()); + auto font_manager = + sk_make_sp(std::move(font_provider)); + blink::FontCollection::ForProcess() + .GetFontCollection() + ->SetDefaultFontManager(std::move(font_manager)); +} + +void ApplicationRunner::FireTerminationCallbackIfNecessary() { + // We have no reason to exist if: + // 1: No previously launched applications are running. + // 2: No bindings exist that may require launching more applications. + if (on_termination_callback_ && active_applications_.size() == 0 && + active_applications_bindings_.size() == 0) { + on_termination_callback_(); + } +} + +} // namespace flutter diff --git a/content_handler/application_runner.h b/content_handler/application_runner.h new file mode 100644 index 0000000000000..fdf5b4420dc0f --- /dev/null +++ b/content_handler/application_runner.h @@ -0,0 +1,79 @@ +// Copyright 2018 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. + +#pragma once + +#include +#include + +#include "application.h" +#include "lib/app/cpp/application_context.h" +#include "lib/app/fidl/application_runner.fidl.h" +#include "lib/fidl/cpp/bindings/binding_set.h" +#include "lib/fsl/tasks/message_loop.h" +#include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/macros.h" + +namespace flutter { + +// Publishes the |component::ApplicationRunner| service and runs applications on +// their own threads. +class ApplicationRunner final : public Application::Delegate, + public component::ApplicationRunner { + public: + ApplicationRunner(fxl::Closure on_termination_callback); + + ~ApplicationRunner(); + + private: + struct ActiveApplication { + std::unique_ptr thread; + std::unique_ptr application; + + ActiveApplication(std::pair, + std::unique_ptr> pair) + : thread(std::move(pair.first)), application(std::move(pair.second)) {} + + ActiveApplication() { + if (thread && application) { + thread->TaskRunner()->PostTask( + fxl::MakeCopyable([application = std::move(application)]() mutable { + application.reset(); + fsl::MessageLoop::GetCurrent()->PostQuitTask(); + })); + thread.reset(); // join + } + } + }; + + fxl::Closure on_termination_callback_; + std::unique_ptr host_context_; + f1dl::BindingSet active_applications_bindings_; + std::unordered_map + active_applications_; + + // |component::ApplicationRunner| + void StartApplication(component::ApplicationPackagePtr application, + component::ApplicationStartupInfoPtr startup_info, + f1dl::InterfaceRequest + controller) override; + + void RegisterApplication( + f1dl::InterfaceRequest request); + + void UnregisterApplication(const Application* application); + + // |Application::Delegate| + void OnApplicationTerminate(const Application* application) override; + + void SetupICU(); + + void SetupGlobalFonts(); + + void FireTerminationCallbackIfNecessary(); + + FXL_DISALLOW_COPY_AND_ASSIGN(ApplicationRunner); +}; + +} // namespace flutter diff --git a/content_handler/compositor_context.cc b/content_handler/compositor_context.cc new file mode 100644 index 0000000000000..efad9ac2b9583 --- /dev/null +++ b/content_handler/compositor_context.cc @@ -0,0 +1,86 @@ +// Copyright 2018 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. + +#include "compositor_context.h" + +#include "flutter/flow/layers/layer_tree.h" +#include "flutter/glue/trace_event.h" + +namespace flutter { + +class ScopedFrame final : public flow::CompositorContext::ScopedFrame { + public: + ScopedFrame(flow::CompositorContext& context, + bool instrumentation_enabled, + SessionConnection& session_connection) + : flow::CompositorContext::ScopedFrame(context, + nullptr, + nullptr, + instrumentation_enabled), + session_connection_(session_connection) {} + + private: + SessionConnection& session_connection_; + + bool Raster(flow::LayerTree& layer_tree, bool ignore_raster_cache) override { + if (!session_connection_.has_metrics()) { + return true; + } + + { + // Preroll the Flutter layer tree. This allows Flutter to perform + // pre-paint optimizations. + TRACE_EVENT0("flutter", "Preroll"); + layer_tree.Preroll(*this, true /* ignore raster cache */); + } + + { + // Traverse the Flutter layer tree so that the necessary session ops to + // represent the frame are enqueued in the underlying session. + TRACE_EVENT0("flutter", "UpdateScene"); + layer_tree.UpdateScene(session_connection_.scene_update_context(), + session_connection_.root_node()); + } + + { + // Flush all pending session ops. + TRACE_EVENT0("flutter", "SessionPresent"); + session_connection_.Present(*this); + } + + return true; + } + + FXL_DISALLOW_COPY_AND_ASSIGN(ScopedFrame); +}; + +CompositorContext::CompositorContext( + const ui::ScenicPtr& scenic, + std::string debug_label, + zx::eventpair import_token, + OnMetricsUpdate session_metrics_did_change_callback, + fxl::Closure session_error_callback) + : debug_label_(std::move(debug_label)), + session_connection_(scenic, + debug_label_, + std::move(import_token), + std::move(session_metrics_did_change_callback), + std::move(session_error_callback)) {} + +CompositorContext::~CompositorContext() = default; + +std::unique_ptr +CompositorContext::AcquireFrame(GrContext* gr_context, + SkCanvas* canvas, + bool instrumentation_enabled) { + // TODO: The AcquireFrame interface is too broad and must be refactored to get + // rid of the context and canvas arguments as those seem to be only used for + // colorspace correctness purposes on the mobile shells. + return std::make_unique(*this, // + instrumentation_enabled, // + session_connection_ // + ); +} + +} // namespace flutter diff --git a/content_handler/compositor_context.h b/content_handler/compositor_context.h new file mode 100644 index 0000000000000..a6e5429c6072c --- /dev/null +++ b/content_handler/compositor_context.h @@ -0,0 +1,39 @@ +// Copyright 2018 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. + +#pragma once + +#include "flutter/flow/compositor_context.h" +#include "garnet/public/lib/ui/scenic/fidl/scenic.fidl-common.h" +#include "lib/fxl/macros.h" +#include "session_connection.h" + +namespace flutter { + +// Holds composition specific state and bindings specific to composition on +// Fuchsia. +class CompositorContext final : public flow::CompositorContext { + public: + CompositorContext(const ui::ScenicPtr& scenic, + std::string debug_label, + zx::eventpair import_token, + OnMetricsUpdate session_metrics_did_change_callback, + fxl::Closure session_error_callback); + + ~CompositorContext() override; + + private: + const std::string debug_label_; + SessionConnection session_connection_; + + // |flow::CompositorContext| + std::unique_ptr AcquireFrame( + GrContext* gr_context, + SkCanvas* canvas, + bool instrumentation_enabled) override; + + FXL_DISALLOW_COPY_AND_ASSIGN(CompositorContext); +}; + +} // namespace flutter diff --git a/content_handler/engine.cc b/content_handler/engine.cc new file mode 100644 index 0000000000000..3349c09bdf1af --- /dev/null +++ b/content_handler/engine.cc @@ -0,0 +1,258 @@ +// Copyright 2018 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. + +#include "engine.h" + +#include + +#include "flutter/common/task_runners.h" +#include "flutter/fml/task_runner.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/run_configuration.h" +#include "lib/fsl/tasks/message_loop.h" +#include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/synchronization/waitable_event.h" +#include "platform_view.h" + +#ifdef ERROR +#undef ERROR +#endif + +namespace flutter { + +Engine::Engine(Delegate& delegate, + std::string thread_label, + component::ApplicationContext& application_context, + blink::Settings settings, + f1dl::InterfaceRequest view_owner, + const UniqueFDIONS& fdio_ns, + f1dl::InterfaceRequest + outgoing_services_request) + : delegate_(delegate), + thread_label_(std::move(thread_label)), + settings_(std::move(settings)), + weak_factory_(this) { + // Launch the threads that will be used to run the shell. These threads will + // be joined in the destructor. + for (auto& thread : host_threads_) { + thread.Run(); + } + + mozart::ViewManagerPtr view_manager; + application_context.ConnectToEnvironmentService(view_manager.NewRequest()); + + zx::eventpair import_token, export_token; + if (zx::eventpair::create(0u, &import_token, &export_token) != ZX_OK) { + FXL_DLOG(ERROR) << "Could not create event pair."; + return; + } + + // Setup the session connection. + ui::ScenicPtr scenic; + view_manager->GetScenic(scenic.NewRequest()); + + // Grab the parent environent services. The platform view may want to access + // some of these services. + component::ServiceProviderPtr parent_environment_service_provider; + application_context.environment()->GetServices( + parent_environment_service_provider.NewRequest()); + + // We need to manually schedule a frame when the session metrics change. + OnMetricsUpdate on_session_metrics_change_callback = std::bind( + &Engine::OnSessionMetricsDidChange, this, std::placeholders::_1); + + fxl::Closure on_session_error_callback = std::bind(&Engine::Terminate, this); + + // Grab the accessibilty context writer that can understand the semtics tree + // on the platform view. + maxwell::ContextWriterPtr accessibility_context_writer; + application_context.ConnectToEnvironmentService( + accessibility_context_writer.NewRequest()); + + // Setup the callback that will instantiate the platform view. + shell::Shell::CreateCallback on_create_platform_view = + fxl::MakeCopyable([debug_label = thread_label_, // + parent_environment_service_provider = + std::move(parent_environment_service_provider), // + view_manager = std::ref(view_manager), // + view_owner = std::move(view_owner), // + scenic = std::move(scenic), // + accessibility_context_writer = + std::move(accessibility_context_writer), // + export_token = std::move(export_token), // + import_token = std::move(import_token), // + on_session_metrics_change_callback, // + on_session_error_callback // + ](shell::Shell& shell) mutable { + return std::make_unique( + shell, // delegate + debug_label, // debug label + shell.GetTaskRunners(), // task runners + std::move(parent_environment_service_provider), // services + view_manager, // view manager + std::move(view_owner), // view owner + std::move(scenic), // scenic + std::move(export_token), // export token + std::move(import_token), // import token + std::move( + accessibility_context_writer), // accessibility context writer + std::move(on_session_metrics_change_callback), // metrics change + std::move(on_session_error_callback) // session_error + ); + }); + + // Setup the callback that will instantiate the rasterizer. + shell::Shell::CreateCallback on_create_rasterizer = + [](shell::Shell& shell) { + return std::make_unique( + shell.GetTaskRunners() // task runners + ); + }; + + // Get the task runners from the managed threads. The current thread will be + // used as the "platform" thread. + blink::TaskRunners task_runners( + thread_label_, // Dart thread labels + fsl::MessageLoop::GetCurrent()->task_runner(), // platform + host_threads_[0].TaskRunner(), // gpu + host_threads_[1].TaskRunner(), // ui + host_threads_[2].TaskRunner() // io + ); + + settings_.root_isolate_create_callback = + std::bind(&Engine::OnMainIsolateStart, this); + + settings_.root_isolate_shutdown_callback = + std::bind([weak = weak_factory_.GetWeakPtr(), + runner = task_runners.GetPlatformTaskRunner()]() { + runner->PostTask([weak = std::move(weak)] { + if (weak) { + weak->OnMainIsolateShutdown(); + } + }); + }); + + shell_ = shell::Shell::Create( + task_runners, // host task runners + settings_, // shell launch settings + on_create_platform_view, // platform view create callback + on_create_rasterizer // rasterizer create callback + ); + + if (!shell_) { + FXL_LOG(ERROR) << "Could not launch the shell with settings: " + << settings_.ToString(); + return; + } + + // Shell has been created. Before we run the engine, setup the isolate + // configurator. + { + PlatformView* platform_view = + static_cast(shell_->GetPlatformView().get()); + auto& view = platform_view->GetMozartView(); + component::ApplicationEnvironmentPtr application_environment; + application_context.ConnectToEnvironmentService( + application_environment.NewRequest()); + + isolate_configurator_ = std::make_unique( + fdio_ns, // + view, // + std::move(application_environment), // + std::move(outgoing_services_request) // + ); + } + + // This platform does not get a separate surface platform view creation + // notification. Fire one eagerly. + shell_->GetPlatformView()->NotifyCreated(); + + // Launch the engine in the appropriate configuration. + auto run_configuration = + shell::RunConfiguration::InferFromSettings(settings_); + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask( + fxl::MakeCopyable([engine = shell_->GetEngine(), // + run_configuration = std::move(run_configuration) // + ]() mutable { + if (!engine || !engine->Run(std::move(run_configuration))) { + FXL_LOG(ERROR) << "Could not (re)launch the engine in configuration"; + } + })); + + UpdateNativeThreadLabelNames(); +} + +Engine::~Engine() { + for (const auto& thread : host_threads_) { + thread.TaskRunner()->PostTask( + []() { fsl::MessageLoop::GetCurrent()->PostQuitTask(); }); + } +} + +void Engine::UpdateNativeThreadLabelNames() const { + auto set_thread_name = [](fxl::RefPtr runner, + std::string prefix, std::string suffix) { + runner->PostTask([name = prefix + suffix]() { + zx::thread::self().set_property(ZX_PROP_NAME, name.c_str(), name.size()); + }); + }; + auto runners = shell_->GetTaskRunners(); + set_thread_name(runners.GetPlatformTaskRunner(), thread_label_, ".platform"); + set_thread_name(runners.GetUITaskRunner(), thread_label_, ".ui"); + set_thread_name(runners.GetGPUTaskRunner(), thread_label_, ".gpu"); + set_thread_name(runners.GetIOTaskRunner(), thread_label_, ".io"); +} + +std::pair Engine::GetEngineReturnCode() const { + std::pair code(false, 0); + if (!shell_) { + return code; + } + fxl::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask( + shell_->GetTaskRunners().GetUITaskRunner(), + [&latch, &code, engine = shell_->GetEngine()]() { + if (engine) { + code = engine->GetUIIsolateReturnCode(); + } + latch.Signal(); + }); + latch.Wait(); + return code; +} + +void Engine::OnMainIsolateStart() { + if (!isolate_configurator_ || + !isolate_configurator_->ConfigureCurrentIsolate()) { + FXL_LOG(ERROR) << "Could not configure some native embedder bindings for a " + "new root isolate."; + } +} + +void Engine::OnMainIsolateShutdown() { + Terminate(); +} + +void Engine::Terminate() { + delegate_.OnEngineTerminate(this); + // Warning. Do not do anything after this point as the delegate may have + // collected this object. +} + +void Engine::OnSessionMetricsDidChange(double device_pixel_ratio) { + if (!shell_) { + return; + } + + shell_->GetTaskRunners().GetPlatformTaskRunner()->PostTask( + [platform_view = shell_->GetPlatformView(), device_pixel_ratio]() { + if (platform_view) { + reinterpret_cast(platform_view.get()) + ->UpdateViewportMetrics(device_pixel_ratio); + } + }); +} + +} // namespace flutter diff --git a/content_handler/engine.h b/content_handler/engine.h new file mode 100644 index 0000000000000..60c0ad7c2f80d --- /dev/null +++ b/content_handler/engine.h @@ -0,0 +1,63 @@ +// Copyright 2018 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. + +#pragma once + +#include "flutter/shell/common/shell.h" +#include "isolate_configurator.h" +#include "lib/app/cpp/application_context.h" +#include "lib/fsl/threading/thread.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" +#include "lib/ui/views/fidl/view_manager.fidl.h" + +namespace flutter { + +// Represents an instance of running Flutter engine along with the threads that +// host the same. +class Engine final { + public: + class Delegate { + public: + virtual void OnEngineTerminate(const Engine* holder) = 0; + }; + + Engine(Delegate& delegate, + std::string thread_label, + component::ApplicationContext& application_context, + blink::Settings settings, + f1dl::InterfaceRequest view_owner, + const UniqueFDIONS& fdio_ns, + f1dl::InterfaceRequest + outgoing_services_request); + + ~Engine(); + + // Returns the Dart return code for the root isolate if one is present. This + // call is thread safe and synchronous. This call must be made infrequently. + std::pair GetEngineReturnCode() const; + + private: + Delegate& delegate_; + const std::string thread_label_; + blink::Settings settings_; + std::array host_threads_; + std::unique_ptr isolate_configurator_; + std::unique_ptr shell_; + fxl::WeakPtrFactory weak_factory_; + + void OnMainIsolateStart(); + + void OnMainIsolateShutdown(); + + void Terminate(); + + void OnSessionMetricsDidChange(double device_pixel_ratio); + + void UpdateNativeThreadLabelNames() const; + + FXL_DISALLOW_COPY_AND_ASSIGN(Engine); +}; + +} // namespace flutter diff --git a/content_handler/fuchsia_font_manager.cc b/content_handler/fuchsia_font_manager.cc index 4e409cae94f6a..877c931130eb4 100644 --- a/content_handler/fuchsia_font_manager.cc +++ b/content_handler/fuchsia_font_manager.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "flutter/content_handler/fuchsia_font_manager.h" +#include "fuchsia_font_manager.h" #include @@ -32,14 +32,14 @@ void UnmapMemory(const void* buffer, void* context) { zx::vmar::root_self().unmap(reinterpret_cast(buffer), size); } -sk_sp MakeSkDataFromBuffer(mem::Buffer data) { - if (!fsl::SizedVmo::IsSizeValid(data.vmo, data.size) || - data.size > std::numeric_limits::max()) { +sk_sp MakeSkDataFromVMO(const fsl::SizedVmoTransportPtr& vmo) { + if (!fsl::SizedVmo::IsSizeValid(vmo->vmo, vmo->size) || + vmo->size > std::numeric_limits::max()) { return nullptr; } - uint64_t size = data.size; + uint64_t size = vmo->size; uintptr_t buffer = 0; - zx_status_t status = zx::vmar::root_self().map(0, data.vmo, 0, size, + zx_status_t status = zx::vmar::root_self().map(0, vmo->vmo, 0, size, ZX_VM_FLAG_PERM_READ, &buffer); if (status != ZX_OK) return nullptr; @@ -49,7 +49,7 @@ sk_sp MakeSkDataFromBuffer(mem::Buffer data) { fonts::FontSlant ToFontSlant(SkFontStyle::Slant slant) { return (slant == SkFontStyle::kItalic_Slant) ? fonts::FontSlant::ITALIC - : fonts::FontSlant::UPRIGHT; + : fonts::FontSlant::UPRIGHT; } } // anonymous namespace @@ -64,7 +64,8 @@ int FuchsiaFontManager::onCountFamilies() const { return 0; } -void FuchsiaFontManager::onGetFamilyName(int index, SkString* familyName) const { +void FuchsiaFontManager::onGetFamilyName(int index, + SkString* familyName) const { FXL_DCHECK(false); } @@ -87,12 +88,13 @@ SkFontStyleSet* FuchsiaFontManager::onMatchFamily( } SkTypeface* FuchsiaFontManager::onMatchFamilyStyle( - const char family_name[], const SkFontStyle& style) const { - fonts::FontRequest request; - request.family = family_name; - request.weight = style.weight(); - request.width = style.width(); - request.slant = ToFontSlant(style.slant()); + const char family_name[], + const SkFontStyle& style) const { + auto request = fonts::FontRequest::New(); + request->family = family_name; + request->weight = style.weight(); + request->width = style.width(); + request->slant = ToFontSlant(style.slant()); fonts::FontResponsePtr response; font_provider_->GetFont( @@ -100,14 +102,13 @@ SkTypeface* FuchsiaFontManager::onMatchFamilyStyle( [&response](fonts::FontResponsePtr r) { response = std::move(r); }); font_provider_.WaitForResponse(); - FXL_DCHECK(response) - << "Unable to contact the font provider. Did you run " - "Flutter in an environment that has a font manager?\n"; - - if (!response) + if (!response) { + FXL_DLOG(ERROR) << "Unable to contact the font provider. Did you run " + "Flutter in an environment that has a font manager?"; return nullptr; + } - sk_sp data = MakeSkDataFromBuffer(std::move(response->data.buffer)); + sk_sp data = MakeSkDataFromVMO(response->data->vmo); if (!data) return nullptr; @@ -127,13 +128,13 @@ SkTypeface* FuchsiaFontManager::onMatchFamilyStyleCharacter( } SkTypeface* FuchsiaFontManager::onMatchFaceStyle(const SkTypeface*, - const SkFontStyle&) const { + const SkFontStyle&) const { FXL_DCHECK(false); return nullptr; } sk_sp FuchsiaFontManager::onMakeFromData(sk_sp, - int ttcIndex) const { + int ttcIndex) const { FXL_DCHECK(false); return nullptr; } @@ -153,7 +154,7 @@ sk_sp FuchsiaFontManager::onMakeFromStreamArgs( } sk_sp FuchsiaFontManager::onMakeFromFile(const char path[], - int ttcIndex) const { + int ttcIndex) const { FXL_DCHECK(false); return nullptr; } diff --git a/content_handler/fuchsia_font_manager.h b/content_handler/fuchsia_font_manager.h index e57d6ef76e72f..ecfb724b85878 100644 --- a/content_handler/fuchsia_font_manager.h +++ b/content_handler/fuchsia_font_manager.h @@ -26,7 +26,7 @@ namespace txt { -class FuchsiaFontManager : public SkFontMgr { +class FuchsiaFontManager final : public SkFontMgr { public: FuchsiaFontManager(fonts::FontProviderPtr provider); diff --git a/content_handler/isolate_configurator.cc b/content_handler/isolate_configurator.cc new file mode 100644 index 0000000000000..d085bea698b95 --- /dev/null +++ b/content_handler/isolate_configurator.cc @@ -0,0 +1,114 @@ +// Copyright 2018 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. + +#include "isolate_configurator.h" + +#include "dart-pkg/fuchsia/sdk_ext/fuchsia.h" +#include "dart-pkg/zircon/sdk_ext/handle.h" +#include "lib/tonic/converter/dart_converter.h" +#include "lib/tonic/dart_state.h" +#include "lib/tonic/logging/dart_error.h" +#include "lib/ui/flutter/sdk_ext/src/natives.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace flutter { + +IsolateConfigurator::IsolateConfigurator( + const UniqueFDIONS& fdio_ns, + mozart::ViewPtr& view, + component::ApplicationEnvironmentPtr application_environment, + f1dl::InterfaceRequest + outgoing_services_request) + : fdio_ns_(fdio_ns), + view_(view), + application_environment_(std::move(application_environment)), + outgoing_services_request_(std::move(outgoing_services_request)) {} + +IsolateConfigurator::~IsolateConfigurator() = default; + +bool IsolateConfigurator::ConfigureCurrentIsolate() { + if (used_) { + return false; + } + used_ = true; + + BindFuchsia(); + BindZircon(); + BindDartIO(); + BindScenic(); + + return true; +} + +// |mozart::NativesDelegate| +mozart::View* IsolateConfigurator::GetMozartView() { + return view_.get(); +} + +void IsolateConfigurator::BindFuchsia() { + fuchsia::dart::Initialize(application_environment_.Unbind(), + std::move(outgoing_services_request_)); +} + +void IsolateConfigurator::BindZircon() { + // Tell dart:zircon about the FDIO namespace configured for this instance. + Dart_Handle zircon_lib = Dart_LookupLibrary(tonic::ToDart("dart:zircon")); + DART_CHECK_VALID(zircon_lib); + + Dart_Handle namespace_type = + Dart_GetType(zircon_lib, tonic::ToDart("_Namespace"), 0, nullptr); + DART_CHECK_VALID(namespace_type); + DART_CHECK_VALID( + Dart_SetField(namespace_type, // + tonic::ToDart("_namespace"), // + tonic::ToDart(reinterpret_cast(fdio_ns_.get())))); +} + +void IsolateConfigurator::BindDartIO() { + // Grab the dart:io lib. + Dart_Handle io_lib = Dart_LookupLibrary(tonic::ToDart("dart:io")); + DART_CHECK_VALID(io_lib); + + // Disable dart:io exit() + Dart_Handle embedder_config_type = + Dart_GetType(io_lib, tonic::ToDart("_EmbedderConfig"), 0, nullptr); + DART_CHECK_VALID(embedder_config_type); + DART_CHECK_VALID(Dart_SetField(embedder_config_type, + tonic::ToDart("_mayExit"), Dart_False())); + + // Tell dart:io about the FDIO namespace configured for this instance. + Dart_Handle namespace_type = + Dart_GetType(io_lib, tonic::ToDart("_Namespace"), 0, nullptr); + DART_CHECK_VALID(namespace_type); + Dart_Handle namespace_args[] = { + Dart_NewInteger(reinterpret_cast(fdio_ns_.get())), // + }; + DART_CHECK_VALID(namespace_args[0]); + DART_CHECK_VALID(Dart_Invoke(namespace_type, tonic::ToDart("_setupNamespace"), + 1, namespace_args)); +} + +void IsolateConfigurator::BindScenic() { + Dart_Handle mozart_internal = + Dart_LookupLibrary(tonic::ToDart("dart:mozart.internal")); + DART_CHECK_VALID(mozart_internal); + DART_CHECK_VALID(Dart_SetNativeResolver(mozart_internal, // + mozart::NativeLookup, // + mozart::NativeSymbol) // + ); + DART_CHECK_VALID(Dart_SetField( + mozart_internal, // + tonic::ToDart("_context"), // + tonic::DartConverter::ToDart(reinterpret_cast( + static_cast(this))))); + mozart::ViewContainerPtr view_container; + view_->GetContainer(view_container.NewRequest()); + DART_CHECK_VALID( + Dart_SetField(mozart_internal, // + tonic::ToDart("_viewContainer"), // + tonic::ToDart(zircon::dart::Handle::Create( + view_container.Unbind().TakeChannel().release())))); +} + +} // namespace flutter diff --git a/content_handler/isolate_configurator.h b/content_handler/isolate_configurator.h new file mode 100644 index 0000000000000..a5da083633ee7 --- /dev/null +++ b/content_handler/isolate_configurator.h @@ -0,0 +1,55 @@ +// Copyright 2018 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. + +#pragma once + +#include "lib/app/fidl/application_environment.fidl.h" +#include "lib/fxl/macros.h" +#include "lib/ui/flutter/sdk_ext/src/natives.h" +#include "lib/ui/views/fidl/view_containers.fidl.h" +#include "lib/ui/views/fidl/views.fidl.h" +#include "unique_fdio_ns.h" + +namespace flutter { + +// Contains all the information necessary to configure a new root isolate. This +// is a single use item. The lifetime of this object must extend past that of +// the root isolate. +class IsolateConfigurator final : mozart::NativesDelegate { + public: + IsolateConfigurator( + const UniqueFDIONS& fdio_ns, + mozart::ViewPtr& view, + component::ApplicationEnvironmentPtr application_environment, + f1dl::InterfaceRequest + outgoing_services_request); + + ~IsolateConfigurator(); + + // Can be used only once and only on the UI thread with the newly created + // isolate already current. + bool ConfigureCurrentIsolate(); + + private: + bool used_ = false; + const UniqueFDIONS& fdio_ns_; + mozart::ViewPtr& view_; + component::ApplicationEnvironmentPtr application_environment_; + f1dl::InterfaceRequest outgoing_services_request_; + + // |mozart::NativesDelegate| + mozart::View* GetMozartView() override; + + void BindFuchsia(); + + void BindZircon(); + + void BindDartIO(); + + void BindScenic(); + + FXL_DISALLOW_COPY_AND_ASSIGN(IsolateConfigurator); +}; + +} // namespace flutter diff --git a/content_handler/main.cc b/content_handler/main.cc index d3eac3c81dcbf..15b8cede5b9b2 100644 --- a/content_handler/main.cc +++ b/content_handler/main.cc @@ -1,16 +1,26 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// Copyright 2018 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. #include +#include -#include "flutter/content_handler/app.h" +#include "application_runner.h" #include "lib/fsl/tasks/message_loop.h" -int main(int argc, const char** argv) { +int main(int argc, char const* argv[]) { fsl::MessageLoop loop; + trace::TraceProvider provider(loop.async()); - flutter_runner::App app; + FXL_DCHECK(provider.is_valid()) << "Trace provider must be valid."; + + FXL_LOG(INFO) << "Flutter application services initialized."; + flutter::ApplicationRunner runner([&loop]() { + loop.PostQuitTask(); + FXL_LOG(INFO) << "Flutter application services terminated. Good bye..."; + }); + loop.Run(); - return 0; + + return EXIT_SUCCESS; } diff --git a/content_handler/platform_view.cc b/content_handler/platform_view.cc new file mode 100644 index 0000000000000..8ac41613e449b --- /dev/null +++ b/content_handler/platform_view.cc @@ -0,0 +1,551 @@ +// Copyright 2018 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. + +#define RAPIDJSON_HAS_STDSTRING 1 + +#include "platform_view.h" + +#include + +#include "flutter/lib/ui/window/pointer_data.h" +#include "lib/app/cpp/connect.h" +#include "third_party/rapidjson/rapidjson/document.h" +#include "third_party/rapidjson/rapidjson/stringbuffer.h" +#include "third_party/rapidjson/rapidjson/writer.h" + +namespace flutter { + +constexpr char kFlutterPlatformChannel[] = "flutter/platform"; +constexpr char kTextInputChannel[] = "flutter/textinput"; +constexpr char kKeyEventChannel[] = "flutter/keyevent"; + +PlatformView::PlatformView( + PlatformView::Delegate& delegate, + std::string debug_label, + blink::TaskRunners task_runners, + component::ServiceProviderPtr parent_environment_service_provider, + mozart::ViewManagerPtr& view_manager, + f1dl::InterfaceRequest view_owner, + ui::ScenicPtr scenic, + zx::eventpair export_token, + zx::eventpair import_token, + maxwell::ContextWriterPtr accessibility_context_writer, + OnMetricsUpdate on_session_metrics_did_change, + fxl::Closure session_error_callback) + : shell::PlatformView(delegate, std::move(task_runners)), + debug_label_(std::move(debug_label)), + view_listener_(this), + input_listener_(this), + ime_client_(this), + scenic_(std::move(scenic)), + accessibility_bridge_(std::move(accessibility_context_writer)), + surface_( + std::make_unique(scenic_, + debug_label_, + std::move(import_token), + std::move(on_session_metrics_did_change), + std::move(session_error_callback))) { + // Create the view. + view_manager->CreateView(view_.NewRequest(), // view + std::move(view_owner), // view owner + view_listener_.NewBinding(), // view listener + std::move(export_token), // export token + debug_label_ // diagnostic label + ); + + // Get the services from the created view. + component::ServiceProviderPtr service_provider; + view_->GetServiceProvider(service_provider.NewRequest()); + + // Get the input connection from the services of the view. + component::ConnectToService(service_provider.get(), + input_connection_.NewRequest()); + + // Set the input listener on the input connection. + input_connection_->SetEventListener(input_listener_.NewBinding()); + + // Access the clipboard. + component::ConnectToService(parent_environment_service_provider.get(), + clipboard_.NewRequest()); + + // Finally! Register the native platform message handlers. + RegisterPlatformMessageHandlers(); +} + +PlatformView::~PlatformView() = default; + +void PlatformView::RegisterPlatformMessageHandlers() { + platform_message_handlers_[kFlutterPlatformChannel] = + std::bind(&PlatformView::HandleFlutterPlatformChannelPlatformMessage, // + this, // + std::placeholders::_1); + platform_message_handlers_[kTextInputChannel] = + std::bind(&PlatformView::HandleFlutterTextInputChannelPlatformMessage, // + this, // + std::placeholders::_1); +} + +mozart::ViewPtr& PlatformView::GetMozartView() { + return view_; +} + +// |mozart::ViewListener| +void PlatformView::OnPropertiesChanged( + mozart::ViewPropertiesPtr properties, + const OnPropertiesChangedCallback& callback) { + UpdateViewportMetrics(properties->view_layout); + callback(); +} + +void PlatformView::UpdateViewportMetrics(const mozart::ViewLayoutPtr& layout) { + if (!layout) { + return; + } + + metrics_.size.width = layout->size->width; + metrics_.size.height = layout->size->height; + + metrics_.padding.left = layout->inset->left; + metrics_.padding.top = layout->inset->top; + metrics_.padding.right = layout->inset->right; + metrics_.padding.bottom = layout->inset->bottom; + + FlushViewportMetrics(); +} + +void PlatformView::UpdateViewportMetrics(double pixel_ratio) { + metrics_.scale = pixel_ratio; + + FlushViewportMetrics(); +} + +void PlatformView::FlushViewportMetrics() { + const auto scale = metrics_.scale; + blink::ViewportMetrics metrics = { + .device_pixel_ratio = static_cast(scale), + + .physical_width = static_cast(metrics_.size.width * scale), + .physical_height = static_cast(metrics_.size.height * scale), + + .physical_padding_top = + static_cast(metrics_.padding.top * scale), + .physical_padding_right = + static_cast(metrics_.padding.right * scale), + .physical_padding_bottom = + static_cast(metrics_.padding.bottom * scale), + .physical_padding_left = + static_cast(metrics_.padding.left * scale), + + .physical_view_inset_top = + static_cast(metrics_.view_inset.top * scale), + .physical_view_inset_right = + static_cast(metrics_.view_inset.right * scale), + .physical_view_inset_bottom = + static_cast(metrics_.view_inset.bottom * scale), + .physical_view_inset_left = + static_cast(metrics_.view_inset.left * scale), + }; + + SetViewportMetrics(metrics); +} + +// |mozart::InputMethodEditorClient| +void PlatformView::DidUpdateState(mozart::TextInputStatePtr state, + mozart::InputEventPtr event) { + rapidjson::Document document; + auto& allocator = document.GetAllocator(); + rapidjson::Value encoded_state(rapidjson::kObjectType); + encoded_state.AddMember("text", state->text.get(), allocator); + encoded_state.AddMember("selectionBase", state->selection->base, allocator); + encoded_state.AddMember("selectionExtent", state->selection->extent, + allocator); + switch (state->selection->affinity) { + case mozart::TextAffinity::UPSTREAM: + encoded_state.AddMember("selectionAffinity", + rapidjson::Value("TextAffinity.upstream"), + allocator); + break; + case mozart::TextAffinity::DOWNSTREAM: + encoded_state.AddMember("selectionAffinity", + rapidjson::Value("TextAffinity.downstream"), + allocator); + break; + } + encoded_state.AddMember("selectionIsDirectional", true, allocator); + encoded_state.AddMember("composingBase", state->composing->start, allocator); + encoded_state.AddMember("composingExtent", state->composing->end, allocator); + + rapidjson::Value args(rapidjson::kArrayType); + args.PushBack(current_text_input_client_, allocator); + args.PushBack(encoded_state, allocator); + + document.SetObject(); + document.AddMember("method", + rapidjson::Value("TextInputClient.updateEditingState"), + allocator); + document.AddMember("args", args, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + + const uint8_t* data = reinterpret_cast(buffer.GetString()); + DispatchPlatformMessage(fxl::MakeRefCounted( + kTextInputChannel, // channel + std::vector(data, data + buffer.GetSize()), // message + nullptr) // response + ); +} + +// |mozart::InputMethodEditorClient| +void PlatformView::OnAction(mozart::InputMethodAction action) { + rapidjson::Document document; + auto& allocator = document.GetAllocator(); + + rapidjson::Value args(rapidjson::kArrayType); + args.PushBack(current_text_input_client_, allocator); + + // Done is currently the only text input action defined by Flutter. + args.PushBack("TextInputAction.done", allocator); + + document.SetObject(); + document.AddMember( + "method", rapidjson::Value("TextInputClient.performAction"), allocator); + document.AddMember("args", args, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + + const uint8_t* data = reinterpret_cast(buffer.GetString()); + DispatchPlatformMessage(fxl::MakeRefCounted( + kTextInputChannel, // channel + std::vector(data, data + buffer.GetSize()), // message + nullptr) // response + ); +} + +// |mozart::InputListener| +void PlatformView::OnEvent(mozart::InputEventPtr event, + const OnEventCallback& callback) { + using Type = mozart::InputEvent::Tag; + switch (event->which()) { + case Type::POINTER: + callback(OnHandlePointerEvent(event->get_pointer())); + return; + case Type::KEYBOARD: + callback(OnHandleKeyboardEvent(event->get_keyboard())); + return; + case Type::FOCUS: + callback(OnHandleFocusEvent(event->get_focus())); + return; + case Type::__UNKNOWN__: + break; + } + + callback(false); +} + +static blink::PointerData::Change GetChangeFromPointerEventPhase( + mozart::PointerEvent::Phase phase) { + switch (phase) { + case mozart::PointerEvent::Phase::ADD: + return blink::PointerData::Change::kAdd; + case mozart::PointerEvent::Phase::HOVER: + return blink::PointerData::Change::kHover; + case mozart::PointerEvent::Phase::DOWN: + return blink::PointerData::Change::kDown; + case mozart::PointerEvent::Phase::MOVE: + return blink::PointerData::Change::kMove; + case mozart::PointerEvent::Phase::UP: + return blink::PointerData::Change::kUp; + case mozart::PointerEvent::Phase::REMOVE: + return blink::PointerData::Change::kRemove; + case mozart::PointerEvent::Phase::CANCEL: + return blink::PointerData::Change::kCancel; + default: + return blink::PointerData::Change::kCancel; + } +} + +static blink::PointerData::DeviceKind GetKindFromPointerType( + mozart::PointerEvent::Type type) { + switch (type) { + case mozart::PointerEvent::Type::TOUCH: + return blink::PointerData::DeviceKind::kTouch; + case mozart::PointerEvent::Type::MOUSE: + return blink::PointerData::DeviceKind::kMouse; + default: + return blink::PointerData::DeviceKind::kTouch; + } +} + +bool PlatformView::OnHandlePointerEvent( + const mozart::PointerEventPtr& pointer) { + blink::PointerData pointer_data; + pointer_data.time_stamp = pointer->event_time / 1000; + pointer_data.change = GetChangeFromPointerEventPhase(pointer->phase); + pointer_data.kind = GetKindFromPointerType(pointer->type); + pointer_data.device = pointer->pointer_id; + pointer_data.physical_x = pointer->x * metrics_.scale; + pointer_data.physical_y = pointer->y * metrics_.scale; + + switch (pointer_data.change) { + case blink::PointerData::Change::kDown: + down_pointers_.insert(pointer_data.device); + break; + case blink::PointerData::Change::kCancel: + case blink::PointerData::Change::kUp: + down_pointers_.erase(pointer_data.device); + break; + case blink::PointerData::Change::kMove: + if (down_pointers_.count(pointer_data.device) == 0) { + pointer_data.change = blink::PointerData::Change::kHover; + } + break; + case blink::PointerData::Change::kAdd: + if (down_pointers_.count(pointer_data.device) != 0) { + FXL_DLOG(ERROR) << "Received add event for down pointer."; + } + break; + case blink::PointerData::Change::kRemove: + if (down_pointers_.count(pointer_data.device) != 0) { + FXL_DLOG(ERROR) << "Received remove event for down pointer."; + } + break; + case blink::PointerData::Change::kHover: + if (down_pointers_.count(pointer_data.device) != 0) { + FXL_DLOG(ERROR) << "Received hover event for down pointer."; + } + break; + } + + auto packet = std::make_unique(1); + packet->SetPointerData(0, pointer_data); + DispatchPointerDataPacket(std::move(packet)); + return true; +} + +bool PlatformView::OnHandleKeyboardEvent( + const mozart::KeyboardEventPtr& keyboard) { + const char* type = nullptr; + if (keyboard->phase == mozart::KeyboardEvent::Phase::PRESSED) { + type = "keydown"; + } else if (keyboard->phase == mozart::KeyboardEvent::Phase::REPEAT) { + type = "keydown"; // TODO change this to keyrepeat + } else if (keyboard->phase == mozart::KeyboardEvent::Phase::RELEASED) { + type = "keyup"; + } + + if (type == nullptr) { + FXL_DLOG(ERROR) << "Unknown key event phase."; + return false; + } + + rapidjson::Document document; + auto& allocator = document.GetAllocator(); + document.SetObject(); + document.AddMember("type", rapidjson::Value(type, strlen(type)), allocator); + document.AddMember("keymap", rapidjson::Value("fuchsia"), allocator); + document.AddMember("hidUsage", keyboard->hid_usage, allocator); + document.AddMember("codePoint", keyboard->code_point, allocator); + document.AddMember("modifiers", keyboard->modifiers, allocator); + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + + const uint8_t* data = reinterpret_cast(buffer.GetString()); + DispatchPlatformMessage(fxl::MakeRefCounted( + kKeyEventChannel, // channel + std::vector(data, data + buffer.GetSize()), // data + nullptr) // response + ); + + return true; +} + +bool PlatformView::OnHandleFocusEvent(const mozart::FocusEventPtr& focus) { + if (!focus->focused && current_text_input_client_ != 0) { + current_text_input_client_ = 0; + if (ime_) { + ime_->Hide(); + ime_ = nullptr; + } + if (ime_client_.is_bound()) { + ime_client_.Unbind(); + } + return true; + } + return false; +} + +// |shell::PlatformView| +std::unique_ptr PlatformView::CreateRenderingSurface() { + // This platform does not repeatly lose and gain a surface connection. So the + // surface is setup once during platform view setup and and returned to the + // shell on the initial (and only) |NotifyCreated| call. + return std::move(surface_); +} + +// |shell::PlatformView| +void PlatformView::HandlePlatformMessage( + fxl::RefPtr message) { + if (!message) { + return; + } + auto found = platform_message_handlers_.find(message->channel()); + if (found == platform_message_handlers_.end()) { + FXL_DLOG(ERROR) + << "Platform view received message on channel '" << message->channel() + << "' with no registed handler. And empty response will be generated. " + "Please implement the native message handler."; + PlatformView::HandlePlatformMessage(std::move(message)); + return; + } + found->second(std::move(message)); +} + +// |shell::PlatformView| +void PlatformView::UpdateSemantics(blink::SemanticsNodeUpdates update) { + accessibility_bridge_.UpdateSemantics(update); +} + +// Channel handler for kFlutterPlatformChannel +void PlatformView::HandleFlutterPlatformChannelPlatformMessage( + fxl::RefPtr message) { + FXL_DCHECK(message->channel() == kFlutterPlatformChannel); + const auto& data = message->data(); + rapidjson::Document document; + document.Parse(reinterpret_cast(data.data()), data.size()); + if (document.HasParseError() || !document.IsObject()) { + return; + } + + auto root = document.GetObject(); + auto method = root.FindMember("method"); + if (method == root.MemberEnd() || !method->value.IsString()) { + return; + } + + fxl::RefPtr response = message->response(); + if (method->value == "Clipboard.setData") { + auto text = root["args"]["text"].GetString(); + clipboard_->Push(text); + response->CompleteEmpty(); + } else if (method->value == "Clipboard.getData") { + clipboard_->Peek([response](const f1dl::String& text) { + rapidjson::StringBuffer json_buffer; + rapidjson::Writer writer(json_buffer); + writer.StartArray(); + writer.StartObject(); + writer.Key("text"); + writer.String(text); + writer.EndObject(); + writer.EndArray(); + std::string result = json_buffer.GetString(); + response->Complete(std::vector{result.begin(), result.end()}); + }); + } else { + response->CompleteEmpty(); + } +} + +// Channel handler for kTextInputChannel +void PlatformView::HandleFlutterTextInputChannelPlatformMessage( + fxl::RefPtr message) { + FXL_DCHECK(message->channel() == kTextInputChannel); + const auto& data = message->data(); + rapidjson::Document document; + document.Parse(reinterpret_cast(data.data()), data.size()); + if (document.HasParseError() || !document.IsObject()) { + return; + } + auto root = document.GetObject(); + auto method = root.FindMember("method"); + if (method == root.MemberEnd() || !method->value.IsString()) { + return; + } + + if (method->value == "TextInput.show") { + if (ime_) { + ime_->Show(); + } + } else if (method->value == "TextInput.hide") { + if (ime_) { + ime_->Hide(); + } + } else if (method->value == "TextInput.setClient") { + current_text_input_client_ = 0; + if (ime_client_.is_bound()) + ime_client_.Unbind(); + ime_ = nullptr; + + auto args = root.FindMember("args"); + if (args == root.MemberEnd() || !args->value.IsArray() || + args->value.Size() != 2) + return; + const auto& configuration = args->value[1]; + if (!configuration.IsObject()) { + return; + } + // TODO(abarth): Read the keyboard type from the configuration. + current_text_input_client_ = args->value[0].GetInt(); + mozart::TextInputStatePtr state = mozart::TextInputState::New(); + state->text = std::string(); + state->selection = mozart::TextSelection::New(); + state->composing = mozart::TextRange::New(); + input_connection_->GetInputMethodEditor( + mozart::KeyboardType::TEXT, mozart::InputMethodAction::DONE, + std::move(state), ime_client_.NewBinding(), ime_.NewRequest()); + } else if (method->value == "TextInput.setEditingState") { + if (ime_) { + auto args_it = root.FindMember("args"); + if (args_it == root.MemberEnd() || !args_it->value.IsObject()) { + return; + } + const auto& args = args_it->value; + mozart::TextInputStatePtr state = mozart::TextInputState::New(); + state->selection = mozart::TextSelection::New(); + state->composing = mozart::TextRange::New(); + // TODO(abarth): Deserialize state. + auto text = args.FindMember("text"); + if (text != args.MemberEnd() && text->value.IsString()) + state->text = text->value.GetString(); + auto selection_base = args.FindMember("selectionBase"); + if (selection_base != args.MemberEnd() && selection_base->value.IsInt()) + state->selection->base = selection_base->value.GetInt(); + auto selection_extent = args.FindMember("selectionExtent"); + if (selection_extent != args.MemberEnd() && + selection_extent->value.IsInt()) + state->selection->extent = selection_extent->value.GetInt(); + auto selection_affinity = args.FindMember("selectionAffinity"); + if (selection_affinity != args.MemberEnd() && + selection_affinity->value.IsString() && + selection_affinity->value == "TextAffinity.upstream") + state->selection->affinity = mozart::TextAffinity::UPSTREAM; + else + state->selection->affinity = mozart::TextAffinity::DOWNSTREAM; + // We ignore selectionIsDirectional because that concept doesn't exist on + // Fuchsia. + auto composing_base = args.FindMember("composingBase"); + if (composing_base != args.MemberEnd() && composing_base->value.IsInt()) + state->composing->start = composing_base->value.GetInt(); + auto composing_extent = args.FindMember("composingExtent"); + if (composing_extent != args.MemberEnd() && + composing_extent->value.IsInt()) + state->composing->end = composing_extent->value.GetInt(); + ime_->SetState(std::move(state)); + } + } else if (method->value == "TextInput.clearClient") { + current_text_input_client_ = 0; + if (ime_client_.is_bound()) + ime_client_.Unbind(); + ime_ = nullptr; + } else { + FXL_DLOG(ERROR) << "Unknown " << message->channel() << " method " + << method->value.GetString(); + } +} + +} // namespace flutter diff --git a/content_handler/platform_view.h b/content_handler/platform_view.h new file mode 100644 index 0000000000000..9888d061352bb --- /dev/null +++ b/content_handler/platform_view.h @@ -0,0 +1,120 @@ +// Copyright 2018 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. + +#pragma once + +#include +#include + +#include "accessibility_bridge.h" +#include "flutter/lib/ui/window/viewport_metrics.h" +#include "flutter/shell/common/platform_view.h" +#include "lib/clipboard/fidl/clipboard.fidl.h" +#include "lib/fidl/cpp/bindings/binding.h" +#include "lib/fxl/macros.h" +#include "lib/ui/input/fidl/input_connection.fidl.h" +#include "lib/ui/views/fidl/view_manager.fidl.h" +#include "lib/ui/views/fidl/views.fidl.h" +#include "surface.h" + +namespace flutter { + +// The per engine component residing on the platform thread is responsible for +// all platform specific integrations. +class PlatformView final : public shell::PlatformView, + public mozart::ViewListener, + public mozart::InputMethodEditorClient, + public mozart::InputListener { + public: + PlatformView( + PlatformView::Delegate& delegate, + std::string debug_label, + blink::TaskRunners task_runners, + component::ServiceProviderPtr parent_environment_service_provider, + mozart::ViewManagerPtr& view_manager, + f1dl::InterfaceRequest view_owner, + ui::ScenicPtr scenic, + zx::eventpair export_token, + zx::eventpair import_token, + maxwell::ContextWriterPtr accessibility_context_writer, + OnMetricsUpdate on_session_metrics_did_change, + fxl::Closure session_error_callback); + + ~PlatformView(); + + void UpdateViewportMetrics(double pixel_ratio); + + mozart::ViewPtr& GetMozartView(); + + private: + const std::string debug_label_; + mozart::ViewPtr view_; + f1dl::Binding view_listener_; + mozart::InputConnectionPtr input_connection_; + f1dl::Binding input_listener_; + int current_text_input_client_ = 0; + f1dl::Binding ime_client_; + mozart::InputMethodEditorPtr ime_; + modular::ClipboardPtr clipboard_; + ui::ScenicPtr scenic_; + AccessibilityBridge accessibility_bridge_; + std::unique_ptr surface_; + blink::LogicalMetrics metrics_; + std::set down_pointers_; + std::map< + std::string /* channel */, + std::function /* message */)> /* handler */> + platform_message_handlers_; + + void RegisterPlatformMessageHandlers(); + + void UpdateViewportMetrics(const mozart::ViewLayoutPtr& layout); + + void FlushViewportMetrics(); + + // |mozart::ViewListener| + void OnPropertiesChanged( + mozart::ViewPropertiesPtr properties, + const OnPropertiesChangedCallback& callback) override; + + // |mozart::InputMethodEditorClient| + void DidUpdateState(mozart::TextInputStatePtr state, + mozart::InputEventPtr event) override; + + // |mozart::InputMethodEditorClient| + void OnAction(mozart::InputMethodAction action) override; + + // |mozart::InputListener| + void OnEvent(mozart::InputEventPtr event, + const OnEventCallback& callback) override; + + bool OnHandlePointerEvent(const mozart::PointerEventPtr& pointer); + + bool OnHandleKeyboardEvent(const mozart::KeyboardEventPtr& keyboard); + + bool OnHandleFocusEvent(const mozart::FocusEventPtr& focus); + + // |shell::PlatformView| + std::unique_ptr CreateRenderingSurface() override; + + // |shell::PlatformView| + void HandlePlatformMessage( + fxl::RefPtr message) override; + + // |shell::PlatformView| + void UpdateSemantics(blink::SemanticsNodeUpdates update) override; + + // Channel handler for kFlutterPlatformChannel + void HandleFlutterPlatformChannelPlatformMessage( + fxl::RefPtr message); + + // Channel handler for kTextInputChannel + void HandleFlutterTextInputChannelPlatformMessage( + fxl::RefPtr message); + + FXL_DISALLOW_COPY_AND_ASSIGN(PlatformView); +}; + +} // namespace flutter diff --git a/content_handler/rasterizer.cc b/content_handler/rasterizer.cc deleted file mode 100644 index b720809b17a45..0000000000000 --- a/content_handler/rasterizer.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/content_handler/rasterizer.h" -#include "flutter/content_handler/vulkan_rasterizer.h" - -namespace flutter_runner { - -Rasterizer::~Rasterizer() = default; - -std::unique_ptr Rasterizer::Create() { - auto vulkan_rasterizer = std::make_unique(); - FXL_CHECK(vulkan_rasterizer) - << "The vulkan rasterizer must be correctly initialized."; - return vulkan_rasterizer; -} - -} // namespace flutter_runner diff --git a/content_handler/rasterizer.h b/content_handler/rasterizer.h deleted file mode 100644 index 398f262a568cd..0000000000000 --- a/content_handler/rasterizer.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2016 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_CONTENT_HANDLER_RASTERIZER_H_ -#define FLUTTER_CONTENT_HANDLER_RASTERIZER_H_ - -#include - -#include - -#include "flutter/flow/layers/layer_tree.h" -#include "lib/fxl/functional/closure.h" -#include "lib/fxl/macros.h" - -namespace flutter_runner { - -class Rasterizer { - public: - virtual ~Rasterizer(); - - static std::unique_ptr Create(); - - virtual void SetScene( - fidl::InterfaceHandle mozart, - zx::eventpair import_token, - fxl::Closure metrics_changed_callback) = 0; - - virtual void Draw(std::unique_ptr layer_tree, - fxl::Closure callback) = 0; -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_RASTERIZER_H_ diff --git a/content_handler/runtime_holder.cc b/content_handler/runtime_holder.cc deleted file mode 100644 index 421731b9691d0..0000000000000 --- a/content_handler/runtime_holder.cc +++ /dev/null @@ -1,911 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/content_handler/runtime_holder.h" - -#include -#include -#include -#include -#include - -#include "dart-pkg/zircon/sdk_ext/handle.h" -#include "flutter/assets/zip_asset_store.h" -#include "flutter/common/threads.h" -#include "flutter/content_handler/accessibility_bridge.h" -#include "flutter/content_handler/rasterizer.h" -#include "flutter/content_handler/service_protocol_hooks.h" -#include "flutter/lib/snapshot/snapshot.h" -#include "flutter/lib/ui/window/pointer_data_packet.h" -#include "flutter/runtime/asset_font_selector.h" -#include "flutter/runtime/dart_controller.h" -#include "flutter/runtime/dart_init.h" -#include "flutter/runtime/runtime_init.h" -#include "lib/app/cpp/connect.h" -#include "lib/fsl/vmo/vector.h" -#include "lib/fxl/files/path.h" -#include "lib/fxl/files/unique_fd.h" -#include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/logging.h" -#include "lib/fxl/time/time_delta.h" -#include "lib/tonic/logging/dart_error.h" -#include "lib/zip/create_unzipper.h" -#include "third_party/dart/runtime/include/dart_api.h" -#include "third_party/rapidjson/rapidjson/document.h" -#include "third_party/rapidjson/rapidjson/stringbuffer.h" -#include "third_party/rapidjson/rapidjson/writer.h" - -using tonic::DartConverter; -using tonic::ToDart; - -namespace flutter_runner { -namespace { - -constexpr char kKernelKey[] = "kernel_blob.bin"; -constexpr char kSnapshotKey[] = "snapshot_blob.bin"; -constexpr char kDylibKey[] = "libapp.so"; -constexpr char kAssetChannel[] = "flutter/assets"; -constexpr char kKeyEventChannel[] = "flutter/keyevent"; -constexpr char kTextInputChannel[] = "flutter/textinput"; -constexpr char kFlutterPlatformChannel[] = "flutter/platform"; -constexpr char kFuchsiaPackageResourceDirectory[] = "pkg/data"; -constexpr char kDartPkgContentsKey[] = "dart-pkg/contents"; - -void SetThreadName(fxl::RefPtr runner, std::string name) { - runner->PostTask([name]() { - zx::thread::self().set_property(ZX_PROP_NAME, name.c_str(), name.size()); - Dart_SetThreadName(name.c_str()); - }); -} - -blink::PointerData::Change GetChangeFromPointerEventPhase( - input::PointerEventPhase phase) { - switch (phase) { - case input::PointerEventPhase::ADD: - return blink::PointerData::Change::kAdd; - case input::PointerEventPhase::HOVER: - return blink::PointerData::Change::kHover; - case input::PointerEventPhase::DOWN: - return blink::PointerData::Change::kDown; - case input::PointerEventPhase::MOVE: - return blink::PointerData::Change::kMove; - case input::PointerEventPhase::UP: - return blink::PointerData::Change::kUp; - case input::PointerEventPhase::REMOVE: - return blink::PointerData::Change::kRemove; - case input::PointerEventPhase::CANCEL: - return blink::PointerData::Change::kCancel; - default: - return blink::PointerData::Change::kCancel; - } -} - -blink::PointerData::DeviceKind GetKindFromPointerType( - input::PointerEventType type) { - switch (type) { - case input::PointerEventType::TOUCH: - return blink::PointerData::DeviceKind::kTouch; - case input::PointerEventType::MOUSE: - return blink::PointerData::DeviceKind::kMouse; - default: - return blink::PointerData::DeviceKind::kTouch; - } -} - -} // namespace - -RuntimeHolder::RuntimeHolder() - : view_listener_binding_(this), - input_listener_binding_(this), - text_input_binding_(this), - weak_factory_(this) {} - -RuntimeHolder::~RuntimeHolder() { - blink::Threads::Gpu()->PostTask( - fxl::MakeCopyable([rasterizer = std::move(rasterizer_)](){ - // Deletes rasterizer. - })); -} - -void RuntimeHolder::Init( - fdio_ns_t* namespc, - std::unique_ptr context, - fidl::InterfaceRequest outgoing_services, - std::vector bundle) { - FXL_DCHECK(!rasterizer_); - rasterizer_ = Rasterizer::Create(); - FXL_DCHECK(rasterizer_); - - namespc_ = namespc; - dirfd_ = fdio_ns_opendir(namespc); - if (dirfd_ == -1) { - FXL_LOG(ERROR) << "Failed to get fd for namespace"; - return; - } - context_ = std::move(context); - outgoing_services_ = std::move(outgoing_services); - - context_->ConnectToEnvironmentService(view_manager_.NewRequest()); - - // TODO(zarah): remove bundle entirely once flx is removed. - InitRootBundle(std::move(bundle)); - - const uint8_t* vm_snapshot_data; - const uint8_t* vm_snapshot_instr; - const uint8_t* default_isolate_snapshot_data; - const uint8_t* default_isolate_snapshot_instr; - if (!Dart_IsPrecompiledRuntime()) { - vm_snapshot_data = ::kDartVmSnapshotData; - vm_snapshot_instr = ::kDartVmSnapshotInstructions; - default_isolate_snapshot_data = ::kDartIsolateCoreSnapshotData; - default_isolate_snapshot_instr = ::kDartIsolateCoreSnapshotInstructions; - } else { - std::vector dylib_blob; - if (!GetAssetAsBuffer(kDylibKey, &dylib_blob)) { - FXL_LOG(ERROR) << "Failed to extract app dylib"; - return; - } - - fsl::SizedVmo dylib_vmo; - if (!fsl::VmoFromVector(dylib_blob, &dylib_vmo)) { - FXL_LOG(ERROR) << "Failed to load app dylib"; - return; - } - - dlerror(); - dylib_handle_ = dlopen_vmo(dylib_vmo.vmo().get(), RTLD_LAZY); - if (dylib_handle_ == nullptr) { - FXL_LOG(ERROR) << "dlopen failed: " << dlerror(); - return; - } - vm_snapshot_data = reinterpret_cast( - dlsym(dylib_handle_, "_kDartVmSnapshotData")); - vm_snapshot_instr = reinterpret_cast( - dlsym(dylib_handle_, "_kDartVmSnapshotInstructions")); - default_isolate_snapshot_data = reinterpret_cast( - dlsym(dylib_handle_, "_kDartIsolateSnapshotData")); - default_isolate_snapshot_instr = reinterpret_cast( - dlsym(dylib_handle_, "_kDartIsolateSnapshotInstructions")); - } - - // TODO(rmacnak): We should generate the AOT vm snapshot separately from - // each app so we can initialize before receiving the first app bundle. - static bool first_app = true; - if (first_app) { - first_app = false; - blink::InitRuntime(vm_snapshot_data, vm_snapshot_instr, - default_isolate_snapshot_data, - default_isolate_snapshot_instr, - /* bundle_path = */ ""); - - // This has to happen after the Dart runtime is initialized. - SetThreadName(blink::Threads::UI(), "ui"); - SetThreadName(blink::Threads::Gpu(), "gpu"); - SetThreadName(blink::Threads::IO(), "io"); - - blink::SetRegisterNativeServiceProtocolExtensionHook( - ServiceProtocolHooks::RegisterHooks); - } - - accessibility_bridge_ = std::make_unique(context_.get()); -} - -void RuntimeHolder::CreateView( - const std::string& script_uri, - fidl::InterfaceRequest view_owner_request, - fidl::InterfaceRequest services) { - if (view_listener_binding_.is_bound()) { - // TODO(jeffbrown): Refactor this to support multiple view instances - // sharing the same underlying root bundle (but with different runtimes). - FXL_LOG(ERROR) << "The view has already been created."; - return; - } - - std::vector kernel; - std::vector snapshot; - bool maybe_running_from_source = false; - if (!Dart_IsPrecompiledRuntime()) { - if (!GetAssetAsBuffer(kKernelKey, &kernel) && - !GetAssetAsBuffer(kSnapshotKey, &snapshot)) { - maybe_running_from_source = true; - FXL_LOG(INFO) << "No kernel or snapshot in root bundle."; - } - } - - // Create the view. - zx::eventpair import_token, export_token; - zx_status_t status = zx::eventpair::create(0u, &import_token, &export_token); - if (status != ZX_OK) { - FXL_LOG(ERROR) << "Could not create an event pair."; - return; - } - views_v1::ViewListenerPtr view_listener; - view_listener_binding_.Bind(view_listener.NewRequest()); - view_manager_->CreateView(view_.NewRequest(), // view - std::move(view_owner_request), // view owner - std::move(view_listener), // view listener - std::move(export_token), // export token - script_uri // diagnostic label - ); - component::ServiceProviderPtr view_services; - view_->GetServiceProvider(view_services.NewRequest()); - - // Listen for input events. - ConnectToService(view_services.get(), input_connection_.NewRequest()); - input::InputListenerPtr input_listener; - input_listener_binding_.Bind(input_listener.NewRequest()); - input_connection_->SetEventListener(std::move(input_listener)); - - // Setup the session. - fidl::InterfaceHandle scenic; - view_manager_->GetScenic(scenic.NewRequest()); - - blink::Threads::Gpu()->PostTask(fxl::MakeCopyable([ - rasterizer = rasterizer_.get(), // - scenic = std::move(scenic), // - import_token = std::move(import_token), // - weak_runtime_holder = GetWeakPtr() - ]() mutable { - ASSERT_IS_GPU_THREAD; - rasterizer->SetScene( - std::move(scenic), std::move(import_token), - // TODO(MZ-222): Ideally we would immediately redraw the previous layer - // tree when the metrics change since there's no need to rerecord it. - // However, we want to make sure there's only one outstanding frame. - // We should improve the frame scheduling so that the rasterizer thread - // can self-schedule re-rasterization. - [weak_runtime_holder] { - // This is on the GPU thread thread. Post to the Platform/UI - // thread for the completion callback. - ASSERT_IS_GPU_THREAD; - blink::Threads::Platform()->PostTask([weak_runtime_holder]() { - // On the Platform/UI thread. - ASSERT_IS_UI_THREAD; - if (weak_runtime_holder) { - weak_runtime_holder->OnRedrawFrame(); - } - }); - }); - })); - runtime_ = blink::RuntimeController::Create(this); - - const uint8_t* isolate_snapshot_data; - const uint8_t* isolate_snapshot_instr; - if (!Dart_IsPrecompiledRuntime()) { - isolate_snapshot_data = ::kDartIsolateCoreSnapshotData; - isolate_snapshot_instr = ::kDartIsolateCoreSnapshotInstructions; - } else { - isolate_snapshot_data = reinterpret_cast( - dlsym(dylib_handle_, "_kDartIsolateSnapshotData")); - isolate_snapshot_instr = reinterpret_cast( - dlsym(dylib_handle_, "_kDartIsolateSnapshotInstructions")); - } - runtime_->CreateDartController(script_uri, isolate_snapshot_data, - isolate_snapshot_instr, dirfd_); - - runtime_->SetViewportMetrics(viewport_metrics_); - - if (Dart_IsPrecompiledRuntime()) { - runtime_->dart_controller()->RunFromPrecompiledSnapshot(); - } else if (!kernel.empty()) { - runtime_->dart_controller()->RunFromKernel(std::move(kernel)); - } else if (maybe_running_from_source) { - std::vector data; - if (!GetAssetAsBuffer(kDartPkgContentsKey, &data)) { - FXL_LOG(ERROR) << "Contents file not found for " << script_uri; - return; - } - std::string package_name(data.begin(), data.end()); - std::string main_dart = "pkg/data/dart-pkg/" + package_name + "/lib/main.dart"; - FXL_LOG(INFO) << "Running from source with entrypoint: '" << main_dart - << "'"; - runtime_->dart_controller()->RunFromSource(main_dart, "pkg/data/dart-pkg/.packages"); - } else { - runtime_->dart_controller()->RunFromScriptSnapshot(snapshot.data(), - snapshot.size()); - } - - runtime_->dart_controller()->dart_state()->SetReturnCodeCallback( - [this](int32_t return_code) { return_code_ = return_code; }); -} - -Dart_Port RuntimeHolder::GetUIIsolateMainPort() { - if (!runtime_) - return ILLEGAL_PORT; - return runtime_->GetMainPort(); -} - -void RuntimeHolder::DidShutdownMainIsolate() { - if (main_isolate_shutdown_callback_) { - main_isolate_shutdown_callback_(); - } -} - -void RuntimeHolder::SetMainIsolateShutdownCallback( - std::function callback) { - main_isolate_shutdown_callback_ = callback; -} - -std::string RuntimeHolder::GetUIIsolateName() { - if (!runtime_) { - return ""; - } - return runtime_->GetIsolateName(); -} - -std::string RuntimeHolder::DefaultRouteName() { - return "/"; -} - -void RuntimeHolder::ScheduleFrame(bool regenerate_layer_tree) { - ASSERT_IS_UI_THREAD; - // TODO(mravn): We assume regenerate_layer_tree is true (and thus ignore - // that we may be able to reuse the current layer tree.) - if (!frame_scheduled_) { - frame_scheduled_ = true; - if (!frame_outstanding_) - PostBeginFrame(); - } -} - -void RuntimeHolder::Render(std::unique_ptr layer_tree) { - if (!frame_outstanding_ || frame_rendering_) { - // TODO(MZ-193): We probably shouldn't be discarding the layer tree here. - // But then, Flutter shouldn't be calling Render() if we didn't call - // BeginFrame(). - return; // Spurious. - } - - frame_rendering_ = true; - - layer_tree->set_construction_time(fxl::TimePoint::Now() - - last_begin_frame_time_); - layer_tree->set_frame_size(SkISize::Make(viewport_metrics_.physical_width, - viewport_metrics_.physical_height)); - layer_tree->set_device_pixel_ratio(viewport_metrics_.device_pixel_ratio); - - // We are on the Platform/UI thread. Post to the GPU thread to render. - ASSERT_IS_PLATFORM_THREAD; - blink::Threads::Gpu()->PostTask(fxl::MakeCopyable([ - rasterizer = rasterizer_.get(), // - layer_tree = std::move(layer_tree), // - weak_runtime_holder = GetWeakPtr() // - ]() mutable { - // On the GPU Thread. - ASSERT_IS_GPU_THREAD; - rasterizer->Draw(std::move(layer_tree), [weak_runtime_holder]() { - // This is on the GPU thread thread. Post to the Platform/UI thread - // for the completion callback. - ASSERT_IS_GPU_THREAD; - blink::Threads::Platform()->PostTask([weak_runtime_holder]() { - // On the Platform/UI thread. - ASSERT_IS_UI_THREAD; - if (weak_runtime_holder) { - weak_runtime_holder->frame_rendering_ = false; - weak_runtime_holder->OnFrameComplete(); - } - }); - }); - })); -} - -void RuntimeHolder::UpdateSemantics(blink::SemanticsNodeUpdates update) { - accessibility_bridge_->UpdateSemantics(update); -} - -void RuntimeHolder::HandlePlatformMessage( - fxl::RefPtr message) { - if (message->channel() == kAssetChannel) { - if (HandleAssetPlatformMessage(message.get())) - return; - } else if (message->channel() == kTextInputChannel) { - if (HandleTextInputPlatformMessage(message.get())) - return; - } else if (message->channel() == kFlutterPlatformChannel) { - if (HandleFlutterPlatformMessage(message.get())) - return; - } - if (auto response = message->response()) - response->CompleteEmpty(); -} - -void RuntimeHolder::DidCreateMainIsolate(Dart_Isolate isolate) { - if (asset_provider_) { - blink::AssetFontSelector::Install(asset_provider_); - } else if (asset_store_) { - blink::AssetFontSelector::Install(asset_store_); - } - InitDartIoInternal(); - InitFuchsia(); - InitZircon(); - InitScenicInternal(); -} - -void RuntimeHolder::InitDartIoInternal() { - Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io")); - - // Set up the namespace. - Dart_Handle namespace_type = - Dart_GetType(io_lib, ToDart("_Namespace"), 0, nullptr); - DART_CHECK_VALID(namespace_type); - Dart_Handle namespace_args[1]; - namespace_args[0] = Dart_NewInteger(reinterpret_cast(namespc_)); - DART_CHECK_VALID(namespace_args[0]); - DART_CHECK_VALID(Dart_Invoke(namespace_type, ToDart("_setupNamespace"), 1, - namespace_args)); - - // Disable dart:io exit() - Dart_Handle embedder_config_type = - Dart_GetType(io_lib, ToDart("_EmbedderConfig"), 0, nullptr); - DART_CHECK_VALID(embedder_config_type); - DART_CHECK_VALID( - Dart_SetField(embedder_config_type, ToDart("_mayExit"), Dart_False())); -} - -void RuntimeHolder::InitFuchsia() { - fidl::InterfaceHandle environment; - context_->ConnectToEnvironmentService(environment.NewRequest()); - fuchsia::dart::Initialize(std::move(environment), - std::move(outgoing_services_)); - - component::ServiceProviderPtr parent_env_service_provider; - context_->environment()->GetServices( - parent_env_service_provider.NewRequest()); - ConnectToService(parent_env_service_provider.get(), clipboard_.NewRequest()); -} - -void RuntimeHolder::InitZircon() { - Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon")); - DART_CHECK_VALID(zircon_lib); - - Dart_Handle namespace_type = - Dart_GetType(zircon_lib, ToDart("_Namespace"), 0, nullptr); - DART_CHECK_VALID(namespace_type); - DART_CHECK_VALID(Dart_SetField(namespace_type, ToDart("_namespace"), - ToDart(reinterpret_cast(namespc_)))); -} - -void RuntimeHolder::InitScenicInternal() { - fidl::InterfaceHandle view_container; - view_->GetContainer(view_container.NewRequest()); - - Dart_Handle mozart_internal = - Dart_LookupLibrary(ToDart("dart:mozart.internal")); - - DART_CHECK_VALID(Dart_SetNativeResolver(mozart_internal, mozart::NativeLookup, - mozart::NativeSymbol)); - - DART_CHECK_VALID( - Dart_SetField(mozart_internal, ToDart("_context"), - DartConverter::ToDart(reinterpret_cast( - static_cast(this))))); - - DART_CHECK_VALID(Dart_SetField(mozart_internal, ToDart("_viewContainer"), - ToDart(zircon::dart::Handle::Create( - view_container.TakeChannel().release())))); -} - -void RuntimeHolder::InitRootBundle(std::vector bundle) { - if (!bundle.empty()) { - root_bundle_data_ = std::move(bundle); - asset_store_ = fxl::MakeRefCounted( - GetUnzipperProviderForRootBundle()); - } else { - fxl::UniqueFD root_dir(fdio_ns_opendir(namespc_)); - if (!root_dir.is_valid()) { - FXL_LOG(ERROR) << "Unable to load root dir"; - return; - } - fxl::UniqueFD data_dir(openat(root_dir.get(), - kFuchsiaPackageResourceDirectory, - O_RDONLY | O_DIRECTORY)); - if (!data_dir.is_valid()) { - FXL_LOG(ERROR) << "Unable to load data dir"; - return; - } - asset_provider_ = - fxl::MakeRefCounted(std::move(data_dir)); - } -} - -views_v1::View* RuntimeHolder::GetMozartView() { - return view_.get(); -} - -bool RuntimeHolder::HandleAssetPlatformMessage( - blink::PlatformMessage* message) { - fxl::RefPtr response = message->response(); - if (!response) - return false; - const auto& data = message->data(); - std::string asset_name(reinterpret_cast(data.data()), - data.size()); - std::vector asset_data; - if (GetAssetAsBuffer(asset_name, &asset_data)) { - response->Complete(std::move(asset_data)); - } else { - response->CompleteEmpty(); - } - return true; -} - -bool RuntimeHolder::GetAssetAsBuffer(const std::string& name, - std::vector* data) { - return (asset_provider_ && - asset_provider_->GetAsBuffer(name, data)) || - (asset_store_ && asset_store_->GetAsBuffer(name, data)); -} - -bool RuntimeHolder::HandleFlutterPlatformMessage( - blink::PlatformMessage* message) { - const auto& data = message->data(); - rapidjson::Document document; - document.Parse(reinterpret_cast(data.data()), data.size()); - if (document.HasParseError() || !document.IsObject()) { - return false; - } - - auto root = document.GetObject(); - auto method = root.FindMember("method"); - if (method == root.MemberEnd() || !method->value.IsString()) { - return false; - } - - fxl::RefPtr response = message->response(); - if (method->value == "Clipboard.setData") { - auto text = root["args"]["text"].GetString(); - clipboard_->Push(text); - response->CompleteEmpty(); - } else if (method->value == "Clipboard.getData") { - clipboard_->Peek([response](fidl::StringPtr text) { - rapidjson::StringBuffer json_buffer; - rapidjson::Writer writer(json_buffer); - writer.StartArray(); - writer.StartObject(); - writer.Key("text"); - writer.String(text.get()); - writer.EndObject(); - writer.EndArray(); - - std::string result = json_buffer.GetString(); - response->Complete(std::vector{result.begin(), result.end()}); - }); - } else { - response->CompleteEmpty(); - } - return true; -} - -bool RuntimeHolder::HandleTextInputPlatformMessage( - blink::PlatformMessage* message) { - const auto& data = message->data(); - - rapidjson::Document document; - document.Parse(reinterpret_cast(data.data()), data.size()); - if (document.HasParseError() || !document.IsObject()) - return false; - auto root = document.GetObject(); - auto method = root.FindMember("method"); - if (method == root.MemberEnd() || !method->value.IsString()) - return false; - - if (method->value == "TextInput.show") { - if (input_method_editor_) { - input_method_editor_->Show(); - } - } else if (method->value == "TextInput.hide") { - if (input_method_editor_) { - input_method_editor_->Hide(); - } - } else if (method->value == "TextInput.setClient") { - current_text_input_client_ = 0; - if (text_input_binding_.is_bound()) - text_input_binding_.Unbind(); - input_method_editor_ = nullptr; - - auto args = root.FindMember("args"); - if (args == root.MemberEnd() || !args->value.IsArray() || - args->value.Size() != 2) - return false; - const auto& configuration = args->value[1]; - if (!configuration.IsObject()) - return false; - // TODO(abarth): Read the keyboard type form the configuration. - current_text_input_client_ = args->value[0].GetInt(); - input::TextInputState state; - state.text = std::string(); - input_connection_->GetInputMethodEditor( - input::KeyboardType::TEXT, input::InputMethodAction::DONE, - std::move(state), text_input_binding_.NewBinding(), - input_method_editor_.NewRequest()); - } else if (method->value == "TextInput.setEditingState") { - if (input_method_editor_) { - auto args_it = root.FindMember("args"); - if (args_it == root.MemberEnd() || !args_it->value.IsObject()) - return false; - const auto& args = args_it->value; - input::TextInputState state; - // TODO(abarth): Deserialize state. - auto text = args.FindMember("text"); - if (text != args.MemberEnd() && text->value.IsString()) - state.text = text->value.GetString(); - auto selection_base = args.FindMember("selectionBase"); - if (selection_base != args.MemberEnd() && selection_base->value.IsInt()) - state.selection.base = selection_base->value.GetInt(); - auto selection_extent = args.FindMember("selectionExtent"); - if (selection_extent != args.MemberEnd() && - selection_extent->value.IsInt()) - state.selection.extent = selection_extent->value.GetInt(); - auto selection_affinity = args.FindMember("selectionAffinity"); - if (selection_affinity != args.MemberEnd() && - selection_affinity->value.IsString() && - selection_affinity->value == "TextAffinity.upstream") - state.selection.affinity = input::TextAffinity::UPSTREAM; - else - state.selection.affinity = input::TextAffinity::DOWNSTREAM; - // We ignore selectionIsDirectional because that concept doesn't exist on - // Fuchsia. - auto composing_base = args.FindMember("composingBase"); - if (composing_base != args.MemberEnd() && composing_base->value.IsInt()) - state.composing.start = composing_base->value.GetInt(); - auto composing_extent = args.FindMember("composingExtent"); - if (composing_extent != args.MemberEnd() && - composing_extent->value.IsInt()) - state.composing.end = composing_extent->value.GetInt(); - input_method_editor_->SetState(std::move(state)); - } - } else if (method->value == "TextInput.clearClient") { - current_text_input_client_ = 0; - if (text_input_binding_.is_bound()) - text_input_binding_.Unbind(); - input_method_editor_ = nullptr; - } else { - FXL_DLOG(ERROR) << "Unknown " << kTextInputChannel << " method " - << method->value.GetString(); - } - - return false; -} - -blink::UnzipperProvider RuntimeHolder::GetUnzipperProviderForRootBundle() { - return [self = GetWeakPtr()]() { - if (!self) - return zip::UniqueUnzipper(); - return zip::CreateUnzipper(&self->root_bundle_data_); - }; -} - -void RuntimeHolder::OnEvent(input::InputEvent event, - OnEventCallback callback) { - bool handled = false; - if (event.is_pointer()) { - const input::PointerEvent& pointer = event.pointer(); - blink::PointerData pointer_data; - pointer_data.time_stamp = pointer.event_time / 1000; - pointer_data.change = GetChangeFromPointerEventPhase(pointer.phase); - pointer_data.kind = GetKindFromPointerType(pointer.type); - pointer_data.device = pointer.pointer_id; - pointer_data.physical_x = pointer.x * viewport_metrics_.device_pixel_ratio; - pointer_data.physical_y = pointer.y * viewport_metrics_.device_pixel_ratio; - // Buttons are single bit values starting with kMousePrimaryButton = 1. - pointer_data.buttons = static_cast(pointer.buttons); - - switch (pointer_data.change) { - case blink::PointerData::Change::kDown: - down_pointers_.insert(pointer_data.device); - break; - case blink::PointerData::Change::kCancel: - case blink::PointerData::Change::kUp: - down_pointers_.erase(pointer_data.device); - break; - case blink::PointerData::Change::kMove: - if (down_pointers_.count(pointer_data.device) == 0) - pointer_data.change = blink::PointerData::Change::kHover; - break; - case blink::PointerData::Change::kAdd: - if (down_pointers_.count(pointer_data.device) != 0) { - FXL_DLOG(ERROR) << "Received add event for down pointer."; - } - break; - case blink::PointerData::Change::kRemove: - if (down_pointers_.count(pointer_data.device) != 0) { - FXL_DLOG(ERROR) << "Received remove event for down pointer."; - } - break; - case blink::PointerData::Change::kHover: - if (down_pointers_.count(pointer_data.device) != 0) { - FXL_DLOG(ERROR) << "Received hover event for down pointer."; - } - break; - } - - blink::PointerDataPacket packet(1); - packet.SetPointerData(0, pointer_data); - runtime_->DispatchPointerDataPacket(packet); - - handled = true; - } else if (event.is_keyboard()) { - const input::KeyboardEvent& keyboard = event.keyboard(); - const char* type = nullptr; - if (keyboard.phase == input::KeyboardEventPhase::PRESSED) - type = "keydown"; - else if (keyboard.phase == input::KeyboardEventPhase::REPEAT) - type = "keydown"; // TODO change this to keyrepeat - else if (keyboard.phase == input::KeyboardEventPhase::RELEASED) - type = "keyup"; - - if (type) { - rapidjson::Document document; - auto& allocator = document.GetAllocator(); - document.SetObject(); - document.AddMember("type", rapidjson::Value(type, strlen(type)), - allocator); - document.AddMember("keymap", rapidjson::Value("fuchsia"), allocator); - document.AddMember("hidUsage", keyboard.hid_usage, allocator); - document.AddMember("codePoint", keyboard.code_point, allocator); - document.AddMember("modifiers", keyboard.modifiers, allocator); - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - document.Accept(writer); - - const uint8_t* data = - reinterpret_cast(buffer.GetString()); - runtime_->DispatchPlatformMessage( - fxl::MakeRefCounted( - kKeyEventChannel, - std::vector(data, data + buffer.GetSize()), nullptr)); - handled = true; - } - } - callback(handled); -} - -void RuntimeHolder::OnPropertiesChanged( - views_v1::ViewProperties properties, - OnPropertiesChangedCallback callback) { - // Attempt to read the device pixel ratio. - float pixel_ratio = 1.f; - if (auto& metrics = properties.display_metrics) { - pixel_ratio = metrics->device_pixel_ratio; - } - - // Apply view property changes. - if (auto& layout = properties.view_layout) { - viewport_metrics_.physical_width = layout->size.width * pixel_ratio; - viewport_metrics_.physical_height = layout->size.height * pixel_ratio; - viewport_metrics_.physical_padding_top = layout->inset.top * pixel_ratio; - viewport_metrics_.physical_padding_right = - layout->inset.right * pixel_ratio; - viewport_metrics_.physical_padding_bottom = - layout->inset.bottom * pixel_ratio; - viewport_metrics_.physical_padding_left = layout->inset.left * pixel_ratio; - viewport_metrics_.device_pixel_ratio = pixel_ratio; - runtime_->SetViewportMetrics(viewport_metrics_); - } - - ScheduleFrame(); - - callback(); -} - -void RuntimeHolder::DidUpdateState(input::TextInputState state, - input::InputEventPtr event) { - rapidjson::Document document; - auto& allocator = document.GetAllocator(); - - rapidjson::Value encoded_state(rapidjson::kObjectType); - encoded_state.AddMember("text", state.text.get(), allocator); - encoded_state.AddMember("selectionBase", state.selection.base, allocator); - encoded_state.AddMember("selectionExtent", state.selection.extent, - allocator); - switch (state.selection.affinity) { - case input::TextAffinity::UPSTREAM: - encoded_state.AddMember("selectionAffinity", - rapidjson::Value("TextAffinity.upstream"), - allocator); - break; - case input::TextAffinity::DOWNSTREAM: - encoded_state.AddMember("selectionAffinity", - rapidjson::Value("TextAffinity.downstream"), - allocator); - break; - } - encoded_state.AddMember("selectionIsDirectional", true, allocator); - encoded_state.AddMember("composingBase", state.composing.start, allocator); - encoded_state.AddMember("composingExtent", state.composing.end, allocator); - - rapidjson::Value args(rapidjson::kArrayType); - args.PushBack(current_text_input_client_, allocator); - args.PushBack(encoded_state, allocator); - - document.SetObject(); - document.AddMember("method", - rapidjson::Value("TextInputClient.updateEditingState"), - allocator); - document.AddMember("args", args, allocator); - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - document.Accept(writer); - - const uint8_t* data = reinterpret_cast(buffer.GetString()); - runtime_->DispatchPlatformMessage(fxl::MakeRefCounted( - kTextInputChannel, std::vector(data, data + buffer.GetSize()), - nullptr)); -} - -void RuntimeHolder::OnAction(input::InputMethodAction action) { - rapidjson::Document document; - auto& allocator = document.GetAllocator(); - - rapidjson::Value args(rapidjson::kArrayType); - args.PushBack(current_text_input_client_, allocator); - - // Done is currently the only text input action defined by Flutter. - args.PushBack("TextInputAction.done", allocator); - - document.SetObject(); - document.AddMember( - "method", rapidjson::Value("TextInputClient.performAction"), allocator); - document.AddMember("args", args, allocator); - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - document.Accept(writer); - - const uint8_t* data = reinterpret_cast(buffer.GetString()); - runtime_->DispatchPlatformMessage(fxl::MakeRefCounted( - kTextInputChannel, std::vector(data, data + buffer.GetSize()), - nullptr)); -} - -fxl::WeakPtr RuntimeHolder::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); -} - -void RuntimeHolder::PostBeginFrame() { - blink::Threads::Platform()->PostTask([weak_runtime_holder = GetWeakPtr()]() { - // On the Platform/UI thread. - ASSERT_IS_UI_THREAD; - if (weak_runtime_holder) { - weak_runtime_holder->BeginFrame(); - } - }); -} - -void RuntimeHolder::BeginFrame() { - ASSERT_IS_UI_THREAD - FXL_DCHECK(frame_scheduled_); - FXL_DCHECK(!frame_outstanding_); - frame_scheduled_ = false; - frame_outstanding_ = true; - int64_t dart_frame_start_micros = Dart_TimelineGetMicros(); - last_begin_frame_time_ = fxl::TimePoint::Now(); - runtime_->BeginFrame(last_begin_frame_time_); - - if (frame_scheduled_) { - // HACK(rmacnak): This assumes 16ms/frame; it should use the frame deadline - // once we have access to it. Compare shell/common/animator.cc. - runtime_->NotifyIdle(dart_frame_start_micros + 16000); - } else { - // We don't have another frame pending, so we're waiting on user input - // or I/O. Allow the Dart VM 100 ms. - runtime_->NotifyIdle(dart_frame_start_micros + 100000); - } -} - -void RuntimeHolder::OnFrameComplete() { - ASSERT_IS_UI_THREAD - FXL_DCHECK(frame_outstanding_); - frame_outstanding_ = false; - if (frame_scheduled_) - PostBeginFrame(); -} - -void RuntimeHolder::OnRedrawFrame() { - if (!frame_outstanding_) - ScheduleFrame(); -} - -} // namespace flutter_runner diff --git a/content_handler/runtime_holder.h b/content_handler/runtime_holder.h deleted file mode 100644 index b9d55d9f9bacc..0000000000000 --- a/content_handler/runtime_holder.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2016 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_CONTENT_HANDLER_RUNTIME_HOLDER_H_ -#define FLUTTER_CONTENT_HANDLER_RUNTIME_HOLDER_H_ - -#include -#include - -#include - -#include "dart-pkg/fuchsia/sdk_ext/fuchsia.h" -#include "flutter/assets/asset_provider.h" -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/assets/unzipper_provider.h" -#include "flutter/assets/zip_asset_store.h" -#include "flutter/content_handler/accessibility_bridge.h" -#include "flutter/flow/layers/layer_tree.h" -#include "flutter/lib/ui/window/viewport_metrics.h" -#include "flutter/runtime/runtime_controller.h" -#include "flutter/runtime/runtime_delegate.h" -#include "lib/app/cpp/application_context.h" -#include -#include -#include -#include "lib/fidl/cpp/binding.h" -#include "lib/fxl/functional/closure.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" -#include "lib/ui/flutter/sdk_ext/src/natives.h" -#include -#include -#include - -namespace flutter_runner { - -class Rasterizer; - -class RuntimeHolder : public blink::RuntimeDelegate, - public mozart::NativesDelegate, - public views_v1::ViewListener, - public input::InputListener, - public input::InputMethodEditorClient { - public: - RuntimeHolder(); - ~RuntimeHolder(); - - void Init(fdio_ns_t* namespc, - std::unique_ptr context, - fidl::InterfaceRequest outgoing_services, - std::vector bundle); - void CreateView(const std::string& script_uri, - fidl::InterfaceRequest view_owner_request, - fidl::InterfaceRequest services); - - Dart_Port GetUIIsolateMainPort(); - std::string GetUIIsolateName(); - - int32_t return_code() { return return_code_; } - - void SetMainIsolateShutdownCallback(std::function callback); - - private: - // |blink::RuntimeDelegate| implementation: - std::string DefaultRouteName() override; - void ScheduleFrame(bool regenerate_layer_tree = true) override; - void Render(std::unique_ptr layer_tree) override; - void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - void HandlePlatformMessage( - fxl::RefPtr message) override; - void DidCreateMainIsolate(Dart_Isolate isolate) override; - void DidShutdownMainIsolate() override; - - // |mozart::NativesDelegate| implementation: - views_v1::View* GetMozartView() override; - - // |input::InputListener| implementation: - void OnEvent(input::InputEvent event, - OnEventCallback callback) override; - - // |views_v1::ViewListener| implementation: - void OnPropertiesChanged( - views_v1::ViewProperties properties, - OnPropertiesChangedCallback callback) override; - - // |input::InputMethodEditorClient| implementation: - void DidUpdateState(input::TextInputState state, - input::InputEventPtr event) override; - void OnAction(input::InputMethodAction action) override; - - fxl::WeakPtr GetWeakPtr(); - - void InitRootBundle(std::vector bundle); - blink::UnzipperProvider GetUnzipperProviderForRootBundle(); - bool HandleAssetPlatformMessage(blink::PlatformMessage* message); - bool GetAssetAsBuffer(const std::string& name, std::vector* data); - bool HandleTextInputPlatformMessage(blink::PlatformMessage* message); - bool HandleFlutterPlatformMessage(blink::PlatformMessage* message); - - void InitDartIoInternal(); - void InitFuchsia(); - void InitZircon(); - void InitScenicInternal(); - - void PostBeginFrame(); - void BeginFrame(); - void OnFrameComplete(); - void OnRedrawFrame(); - void Invalidate(); - - fdio_ns_t* namespc_; - int dirfd_; - std::unique_ptr context_; - fidl::InterfaceRequest outgoing_services_; - std::vector root_bundle_data_; - // TODO(zarah): Remove asset_store_ when flx is completely removed - fxl::RefPtr asset_store_; - fxl::RefPtr asset_provider_; - void* dylib_handle_ = nullptr; - std::unique_ptr rasterizer_; - std::unique_ptr runtime_; - blink::ViewportMetrics viewport_metrics_; - views_v1::ViewManagerPtr view_manager_; - fidl::Binding view_listener_binding_; - fidl::Binding input_listener_binding_; - input::InputConnectionPtr input_connection_; - views_v1::ViewPtr view_; - std::unordered_set down_pointers_; - input::InputMethodEditorPtr input_method_editor_; - fidl::Binding text_input_binding_; - int current_text_input_client_ = 0; - fxl::TimePoint last_begin_frame_time_; - bool frame_outstanding_ = false; - bool frame_scheduled_ = false; - bool frame_rendering_ = false; - int32_t return_code_ = 0; - - fxl::WeakPtrFactory weak_factory_; - - std::unique_ptr accessibility_bridge_; - - std::function main_isolate_shutdown_callback_; - - modular::ClipboardPtr clipboard_; - - FXL_DISALLOW_COPY_AND_ASSIGN(RuntimeHolder); -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_RUNTIME_HOLDER_H_ diff --git a/content_handler/service_protocol_hooks.cc b/content_handler/service_protocol_hooks.cc deleted file mode 100644 index 9a91254f13488..0000000000000 --- a/content_handler/service_protocol_hooks.cc +++ /dev/null @@ -1,164 +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. - -#include "flutter/content_handler/service_protocol_hooks.h" - -#include - -#include -#include - -#include "flutter/common/threads.h" -#include "flutter/content_handler/app.h" -#include "lib/fxl/memory/weak_ptr.h" - -namespace flutter_runner { -namespace { - -constexpr char kViewIdPrefx[] = "_flutterView/"; -constexpr size_t kViewIdPrefxLength = sizeof(kViewIdPrefx) - 1; - -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 void AppendIsolateRef(std::stringstream* stream, - int64_t main_port, - const std::string name) { - *stream << "{\"type\":\"@Isolate\",\"fixedId\":true,\"id\":\"isolates/"; - *stream << main_port << "\",\"name\":\"" << name << "\","; - *stream << "\"number\":\"" << main_port << "\"}"; -} - -static void AppendFlutterView(std::stringstream* stream, - uintptr_t view_id, - int64_t isolate_id, - const std::string isolate_name) { - *stream << "{\"type\":\"FlutterView\", \"id\": \"" << kViewIdPrefx << "0x" - << std::hex << view_id << std::dec << "\""; - if (isolate_id != ILLEGAL_PORT) { - // Append the isolate (if it exists). - *stream << "," - << "\"isolate\":"; - AppendIsolateRef(stream, isolate_id, isolate_name); - } - *stream << "}"; -} - -} // namespace - -void ServiceProtocolHooks::RegisterHooks(bool running_precompiled_code) { - // Listing of FlutterViews. - Dart_RegisterRootServiceRequestCallback(kListViewsExtensionName, &ListViews, - nullptr); - - Dart_RegisterRootServiceRequestCallback(kSetAssetBundlePathExtensionName, - &SetAssetBundlePath, nullptr); -} - -const char* ServiceProtocolHooks::kListViewsExtensionName = - "_flutter.listViews"; - -bool ServiceProtocolHooks::ListViews(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - // Ask the App for the list of platform views. This will run a task on - // the UI thread before returning. - App& app = App::Shared(); - std::vector platform_views; - app.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++) { - uintptr_t view_id = it->view_id; - int64_t isolate_id = it->isolate_id; - const std::string& isolate_name = it->isolate_name; - if (!view_id) { - continue; - } - if (prefix_comma) { - response << ','; - } else { - prefix_comma = true; - } - AppendFlutterView(&response, view_id, isolate_id, isolate_name); - } - response << "]}"; - // Copy the response. - *json_object = strdup(response.str().c_str()); - return true; -} - -const char* ServiceProtocolHooks::kSetAssetBundlePathExtensionName = - "_flutter.setAssetBundlePath"; - -bool ServiceProtocolHooks::SetAssetBundlePath(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - const char* view_id_str = - ValueForKey(param_keys, param_values, num_params, "viewId"); - - // Ask the App for the list of platform views. This will run a task on - // the UI thread before returning. - App& app = App::Shared(); - std::vector platform_views; - app.WaitForPlatformViewIds(&platform_views); - - // Convert the actual flutter view hex id into a number. - uintptr_t view_id_as_num = - std::stoull((view_id_str + kViewIdPrefxLength), nullptr, 16); - - // The view existed and the isolate was created. Success. - std::stringstream response; - response << "{\"type\":\"Success\"," - << "\"view\":"; - for (auto it = platform_views.begin(); it != platform_views.end(); it++) { - uintptr_t view_id = it->view_id; - int64_t isolate_id = it->isolate_id; - const std::string& isolate_name = it->isolate_name; - if (!view_id || view_id != view_id_as_num) { - continue; - } - - // TODO(DX): Set up asset bundle path for the isolate. - - AppendFlutterView(&response, view_id, isolate_id, isolate_name); - break; - } - response << "}"; - *json_object = strdup(response.str().c_str()); - return true; -} - -} // namespace flutter_runner diff --git a/content_handler/service_protocol_hooks.h b/content_handler/service_protocol_hooks.h deleted file mode 100644 index 479fb71471f1e..0000000000000 --- a/content_handler/service_protocol_hooks.h +++ /dev/null @@ -1,37 +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_CONTENT_HANDLER_SERVICE_PROTOCOL_HOOKS_H_ -#define FLUTTER_CONTENT_HANDLER_SERVICE_PROTOCOL_HOOKS_H_ - -#include "lib/fxl/synchronization/waitable_event.h" -#include "third_party/dart/runtime/include/dart_tools_api.h" - -namespace flutter_runner { - -class ServiceProtocolHooks { - public: - static void RegisterHooks(bool running_precompiled_code); - - private: - static const char* kListViewsExtensionName; - static bool ListViews(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); - - static const char* kSetAssetBundlePathExtensionName; - static bool SetAssetBundlePath(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_SERVICE_PROTOCOL_HOOKS_H_ diff --git a/content_handler/session_connection.cc b/content_handler/session_connection.cc index b496ae37f40f2..870020abb670f 100644 --- a/content_handler/session_connection.cc +++ b/content_handler/session_connection.cc @@ -2,72 +2,69 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/content_handler/session_connection.h" -#include "lib/fidl/cpp/optional.h" +#include "session_connection.h" + #include "lib/ui/scenic/fidl_helpers.h" -namespace flutter_runner { +namespace flutter { -SessionConnection::SessionConnection(ui::ScenicPtr scenic, - zx::eventpair import_token) - : session_(scenic.get()), +SessionConnection::SessionConnection( + const ui::ScenicPtr& scenic, + std::string debug_label, + zx::eventpair import_token, + OnMetricsUpdate session_metrics_did_change_callback, + fxl::Closure session_error_callback) + : debug_label_(std::move(debug_label)), + session_(scenic.get()), root_node_(&session_), surface_producer_(std::make_unique(&session_)), - scene_update_context_(&session_, surface_producer_.get()) { - ASSERT_IS_GPU_THREAD; - - session_.set_error_handler( - std::bind(&SessionConnection::OnSessionError, this)); + scene_update_context_(&session_, surface_producer_.get()), + metrics_changed_callback_( + std::move(session_metrics_did_change_callback)) { + session_.set_error_handler(std::move(session_error_callback)); session_.set_event_handler(std::bind(&SessionConnection::OnSessionEvents, this, std::placeholders::_1)); root_node_.Bind(std::move(import_token)); - root_node_.SetEventMask(gfx::kMetricsEventMask); - session_.Present(0, [](images::PresentationInfo info) {}); - - present_callback_ = - std::bind(&SessionConnection::OnPresent, this, std::placeholders::_1); + root_node_.SetEventMask(ui::gfx::kMetricsEventMask); + session_.Present(0, [](ui::PresentationInfoPtr info) {}); } -SessionConnection::~SessionConnection() { - ASSERT_IS_GPU_THREAD; -} +SessionConnection::~SessionConnection() = default; -void SessionConnection::OnSessionError() { - ASSERT_IS_GPU_THREAD; - // TODO: Not this. - FXL_CHECK(false) << "Session connection was terminated."; -} +void SessionConnection::OnSessionEvents(f1dl::Array events) { + using Type = ui::gfx::Event::Tag; -void SessionConnection::OnSessionEvents(fidl::VectorPtr events) { - gfx::Metrics* new_metrics; - for (auto& event : *events) { - if (event.is_gfx() && event.gfx().is_metrics() && - event.gfx().metrics().node_id == root_node_.id()) { - new_metrics = &event.gfx().metrics().metrics; + for (auto& raw_event : *events) { + if (!raw_event->is_gfx()) { + continue; } - } - if (!new_metrics) - return; - scene_update_context_.set_metrics(fidl::MakeOptional(std::move(*new_metrics))); - - if (metrics_changed_callback_) - metrics_changed_callback_(); + auto& event = raw_event->get_gfx(); + + switch (event->which()) { + case Type::METRICS: { + if (event->get_metrics()->node_id == root_node_.id()) { + auto& metrics = event->get_metrics()->metrics; + double device_pixel_ratio = metrics->scale_x; + scene_update_context_.set_metrics(std::move(metrics)); + if (metrics_changed_callback_) { + metrics_changed_callback_(device_pixel_ratio); + } + } + } break; + default: + break; + } + } } -void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame, - fxl::Closure on_present_callback) { - ASSERT_IS_GPU_THREAD; - FXL_DCHECK(pending_on_present_callback_ == nullptr); - FXL_DCHECK(on_present_callback != nullptr); - pending_on_present_callback_ = on_present_callback; - +void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame) { // Flush all session ops. Paint tasks have not yet executed but those are // fenced. The compositor can start processing ops while we finalize paint // tasks. - session_.Present(0, // presentation_time. Placeholder for now. - present_callback_ // callback + session_.Present(0, // presentation_time. (placeholder). + [](ui::PresentationInfoPtr) {} // callback ); // Execute paint tasks and signal fences. @@ -77,22 +74,15 @@ void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame, // book-keeping on buffer caches. surface_producer_->OnSurfacesPresented(std::move(surfaces_to_submit)); - // Prepare for the next frame. - EnqueueClearCommands(); -} - -void SessionConnection::OnPresent(images::PresentationInfo info) { - ASSERT_IS_GPU_THREAD; - auto callback = pending_on_present_callback_; - pending_on_present_callback_ = nullptr; - callback(); + // Prepare for the next frame. These ops won't be processed till the next + // present. + EnqueueClearOps(); } -void SessionConnection::EnqueueClearCommands() { - ASSERT_IS_GPU_THREAD; +void SessionConnection::EnqueueClearOps() { // We are going to be sending down a fresh node hierarchy every frame. So just - // enqueue a detach command on the imported root node. + // enqueue a detach op on the imported root node. session_.Enqueue(scenic_lib::NewDetachChildrenCommand(root_node_.id())); } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/session_connection.h b/content_handler/session_connection.h index a80ba3a2235d2..e4f39d314c98f 100644 --- a/content_handler/session_connection.h +++ b/content_handler/session_connection.h @@ -2,70 +2,62 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ -#define FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ +#pragma once #include -#include "flutter/common/threads.h" -#include "flutter/content_handler/vulkan_surface_producer.h" #include "flutter/flow/compositor_context.h" #include "flutter/flow/scene_update_context.h" -#include "lib/fidl/cpp/interface_handle.h" +#include "lib/fidl/cpp/bindings/interface_handle.h" #include "lib/fxl/functional/closure.h" #include "lib/fxl/macros.h" #include "lib/ui/scenic/client/resources.h" #include "lib/ui/scenic/client/session.h" +#include "vulkan_surface_producer.h" -namespace flutter_runner { +namespace flutter { -class SessionConnection { +using OnMetricsUpdate = std::function; + +// The component residing on the GPU thread that is responsible for +// maintaining the Scenic session connection and presenting node updates. +class SessionConnection final { public: - SessionConnection(ui::ScenicPtr scenic, zx::eventpair import_token); + SessionConnection(const ui::ScenicPtr& scenic, + std::string debug_label, + zx::eventpair import_token, + OnMetricsUpdate session_metrics_did_change_callback, + fxl::Closure session_error_callback); ~SessionConnection(); bool has_metrics() const { return scene_update_context_.has_metrics(); } - const gfx::MetricsPtr& metrics() const { + const ui::gfx::MetricsPtr& metrics() const { return scene_update_context_.metrics(); } - void set_metrics_changed_callback(fxl::Closure callback) { - metrics_changed_callback_ = std::move(callback); - } - flow::SceneUpdateContext& scene_update_context() { return scene_update_context_; } - scenic_lib::ImportNode& root_node() { - ASSERT_IS_GPU_THREAD; - return root_node_; - } + scenic_lib::ImportNode& root_node() { return root_node_; } - void Present(flow::CompositorContext::ScopedFrame& frame, - fxl::Closure on_present_callback); + void Present(flow::CompositorContext::ScopedFrame& frame); private: + const std::string debug_label_; scenic_lib::Session session_; scenic_lib::ImportNode root_node_; - scenic_lib::Session::PresentCallback present_callback_; - fxl::Closure pending_on_present_callback_; std::unique_ptr surface_producer_; flow::SceneUpdateContext scene_update_context_; - fxl::Closure metrics_changed_callback_; - - void OnSessionError(); - void OnSessionEvents(fidl::VectorPtr events); + OnMetricsUpdate metrics_changed_callback_; - void EnqueueClearCommands(); + void OnSessionEvents(f1dl::Array events); - void OnPresent(images::PresentationInfo info); + void EnqueueClearOps(); FXL_DISALLOW_COPY_AND_ASSIGN(SessionConnection); }; -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ +} // namespace flutter diff --git a/content_handler/surface.cc b/content_handler/surface.cc new file mode 100644 index 0000000000000..8efe1975fbfdb --- /dev/null +++ b/content_handler/surface.cc @@ -0,0 +1,73 @@ +// Copyright 2018 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. + +#include "surface.h" + +#include +#include +#include +#include + +#include "lib/fxl/files/unique_fd.h" + +namespace flutter { + +Surface::Surface(const ui::ScenicPtr& scenic, + std::string debug_label, + zx::eventpair import_token, + OnMetricsUpdate session_metrics_did_change_callback, + fxl::Closure session_error_callback) + : shell::Surface(std::make_unique( + scenic, + debug_label, + std::move(import_token), + std::move(session_metrics_did_change_callback), + std::move(session_error_callback))), + debug_label_(debug_label) {} + +Surface::~Surface() = default; + +// |shell::Surface| +bool Surface::IsValid() { + return valid_; +} + +// |shell::Surface| +std::unique_ptr Surface::AcquireFrame( + const SkISize& size) { + return std::make_unique( + nullptr, [](const shell::SurfaceFrame& surface_frame, SkCanvas* canvas) { + return true; + }); +} + +// |shell::Surface| +GrContext* Surface::GetContext() { + return nullptr; +} + +static zx_status_t DriverWatcher(int dirfd, + int event, + const char* fn, + void* cookie) { + if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) { + return ZX_ERR_STOP; + } + return ZX_OK; +} + +bool Surface::CanConnectToDisplay() { + constexpr char kDisplayDriverClass[] = "/dev/class/display"; + fxl::UniqueFD fd(open(kDisplayDriverClass, O_DIRECTORY | O_RDONLY)); + if (fd.get() < 0) { + FXL_DLOG(ERROR) << "Failed to open " << kDisplayDriverClass; + return false; + } + + zx_status_t status = fdio_watch_directory( + fd.get(), DriverWatcher, zx_deadline_after(ZX_SEC(1)), nullptr); + return status == ZX_ERR_STOP; +} + +} // namespace flutter diff --git a/content_handler/surface.h b/content_handler/surface.h new file mode 100644 index 0000000000000..4ad27aaf540f3 --- /dev/null +++ b/content_handler/surface.h @@ -0,0 +1,47 @@ +// Copyright 2018 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. + +#pragma once + +#include "compositor_context.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/shell/common/surface.h" +#include "lib/fxl/macros.h" + +namespace flutter { + +// The interface between the Flutter rasterizer and the underlying platform. May +// be constructed on any thread but will be used by the engine only on the GPU +// thread. +class Surface final : public shell::Surface { + public: + Surface(const ui::ScenicPtr& scenic, + std::string debug_label, + zx::eventpair import_token, + OnMetricsUpdate session_metrics_did_change_callback, + fxl::Closure session_error_callback); + + ~Surface() override; + + private: + const bool valid_ = CanConnectToDisplay(); + const std::string debug_label_; + std::unique_ptr compositor_context_; + + // |shell::Surface| + bool IsValid() override; + + // |shell::Surface| + std::unique_ptr AcquireFrame( + const SkISize& size) override; + + // |shell::Surface| + GrContext* GetContext() override; + + static bool CanConnectToDisplay(); + + FXL_DISALLOW_COPY_AND_ASSIGN(Surface); +}; + +} // namespace flutter diff --git a/content_handler/task_observers.cc b/content_handler/task_observers.cc new file mode 100644 index 0000000000000..f23265e7b1653 --- /dev/null +++ b/content_handler/task_observers.cc @@ -0,0 +1,43 @@ +// Copyright 2018 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. + +#include "task_observers.h" + +#include + +#include "lib/fsl/tasks/message_loop.h" + +namespace flutter { + +thread_local std::map tTaskObservers; + +static void ExecuteAfterTaskObservers() { + for (const auto& callback : tTaskObservers) { + callback.second(); + } +} + +void CurrentMessageLoopAddAfterTaskObserver(intptr_t key, + fxl::Closure observer) { + if (!observer) { + return; + } + + if (tTaskObservers.size() == 0) { + fsl::MessageLoop::GetCurrent()->SetAfterTaskCallback( + std::bind(&ExecuteAfterTaskObservers)); + } + + tTaskObservers[key] = observer; +} + +void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key) { + tTaskObservers.erase(key); + + if (tTaskObservers.size() == 0) { + fsl::MessageLoop::GetCurrent()->ClearAfterTaskCallback(); + } +} + +} // namespace flutter diff --git a/content_handler/task_observers.h b/content_handler/task_observers.h new file mode 100644 index 0000000000000..53f6b96222000 --- /dev/null +++ b/content_handler/task_observers.h @@ -0,0 +1,16 @@ +// Copyright 2018 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. + +#pragma once + +#include "lib/fxl/functional/closure.h" + +namespace flutter { + +void CurrentMessageLoopAddAfterTaskObserver(intptr_t key, + fxl::Closure observer); + +void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key); + +} // namespace flutter diff --git a/content_handler/unique_fdio_ns.h b/content_handler/unique_fdio_ns.h new file mode 100644 index 0000000000000..726137d729f85 --- /dev/null +++ b/content_handler/unique_fdio_ns.h @@ -0,0 +1,34 @@ +// Copyright 2018 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. + +#pragma once + +#include "fdio/namespace.h" +#include "lib/fxl/logging.h" +#include "lib/fxl/memory/unique_object.h" + +namespace flutter { + +struct UniqueFDIONSTraits { + static fdio_ns_t* InvalidValue() { return nullptr; } + + static bool IsValid(fdio_ns_t* ns) { return ns != InvalidValue(); } + + static void Free(fdio_ns_t* ns) { + auto status = fdio_ns_destroy(ns); + FXL_DCHECK(status == ZX_OK); + } +}; + +using UniqueFDIONS = fxl::UniqueObject; + +inline UniqueFDIONS UniqueFDIONSCreate() { + fdio_ns_t* ns = nullptr; + if (fdio_ns_create(&ns) == ZX_OK) { + return UniqueFDIONS{ns}; + } + return UniqueFDIONS{nullptr}; +} + +} // namespace flutter diff --git a/content_handler/vulkan_rasterizer.cc b/content_handler/vulkan_rasterizer.cc deleted file mode 100644 index 25f90c460ce3f..0000000000000 --- a/content_handler/vulkan_rasterizer.cc +++ /dev/null @@ -1,117 +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. - -#include "flutter/content_handler/vulkan_rasterizer.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include "flutter/common/threads.h" -#include "flutter/glue/trace_event.h" -#include "lib/fxl/files/unique_fd.h" - -namespace flutter_runner { - -constexpr char kGpuDriverClass[] = "/dev/class/gpu"; - -static zx_status_t DriverWatcher(int dirfd, - int event, - const char* fn, - void* cookie) { - if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) { - return ZX_ERR_STOP; - } - return ZX_OK; -} - -bool WaitForFirstGpuDriver() { - fxl::UniqueFD fd(open(kGpuDriverClass, O_DIRECTORY | O_RDONLY)); - if (fd.get() < 0) { - FXL_DLOG(ERROR) << "Failed to open " << kGpuDriverClass; - return false; - } - - zx_status_t status = fdio_watch_directory( - fd.get(), DriverWatcher, zx_deadline_after(ZX_SEC(5)), nullptr); - return status == ZX_ERR_STOP; -} - -VulkanRasterizer::VulkanRasterizer() : compositor_context_(nullptr) { - valid_ = WaitForFirstGpuDriver(); -} - -VulkanRasterizer::~VulkanRasterizer() = default; - -bool VulkanRasterizer::IsValid() const { - return valid_; -} - -void VulkanRasterizer::SetScene(fidl::InterfaceHandle scenic, - zx::eventpair import_token, - fxl::Closure metrics_changed_callback) { - ASSERT_IS_GPU_THREAD; - FXL_DCHECK(valid_ && !session_connection_); - session_connection_ = std::make_unique( - scenic.Bind(), std::move(import_token)); - session_connection_->set_metrics_changed_callback( - std::move(metrics_changed_callback)); -} - -void VulkanRasterizer::Draw(std::unique_ptr layer_tree, - fxl::Closure callback) { - ASSERT_IS_GPU_THREAD; - FXL_DCHECK(callback != nullptr); - - if (layer_tree == nullptr) { - FXL_LOG(ERROR) << "Layer tree was not valid."; - callback(); - return; - } - - if (!session_connection_) { - FXL_LOG(ERROR) << "Session was not valid."; - callback(); - return; - } - - if (!session_connection_->has_metrics()) { - // Still awaiting metrics. Will redraw when we get them. - callback(); - return; - } - - compositor_context_.engine_time().SetLapTime(layer_tree->construction_time()); - - flow::CompositorContext::ScopedFrame frame = compositor_context_.AcquireFrame( - nullptr, nullptr, true /* instrumentation enabled */); - { - // Preroll the Flutter layer tree. This allows Flutter to perform pre-paint - // optimizations. - TRACE_EVENT0("flutter", "Preroll"); - layer_tree->Preroll(frame, session_connection_->metrics().get()); - } - - { - // Traverse the Flutter layer tree so that the necessary session ops to - // represent the frame are enqueued in the underlying session. - TRACE_EVENT0("flutter", "UpdateScene"); - layer_tree->UpdateScene(session_connection_->scene_update_context(), - session_connection_->root_node()); - } - - { - // Flush all pending session ops. - TRACE_EVENT0("flutter", "SessionPresent"); - session_connection_->Present( - frame, [callback = std::move(callback)]() { callback(); }); - } -} - -} // namespace flutter_runner diff --git a/content_handler/vulkan_rasterizer.h b/content_handler/vulkan_rasterizer.h deleted file mode 100644 index c3ae211553f5a..0000000000000 --- a/content_handler/vulkan_rasterizer.h +++ /dev/null @@ -1,42 +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_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ -#define FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ - -#include - -#include "flutter/content_handler/rasterizer.h" -#include "flutter/content_handler/session_connection.h" -#include "flutter/flow/compositor_context.h" -#include "lib/fxl/macros.h" - -namespace flutter_runner { - -class VulkanRasterizer : public Rasterizer { - public: - VulkanRasterizer(); - - ~VulkanRasterizer() override; - - bool IsValid() const; - - void SetScene(fidl::InterfaceHandle scenic, - zx::eventpair import_token, - fxl::Closure metrics_changed_callback) override; - - void Draw(std::unique_ptr layer_tree, - fxl::Closure callback) override; - - private: - flow::CompositorContext compositor_context_; - std::unique_ptr session_connection_; - bool valid_; - - FXL_DISALLOW_COPY_AND_ASSIGN(VulkanRasterizer); -}; - -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ diff --git a/content_handler/vulkan_surface.cc b/content_handler/vulkan_surface.cc index 47ac87e375e81..c78ad6c127545 100644 --- a/content_handler/vulkan_surface.cc +++ b/content_handler/vulkan_surface.cc @@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "vulkan_surface.h" + #include -#include "flutter/content_handler/vulkan_surface.h" -#include "flutter/common/threads.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" -namespace flutter_runner { +namespace flutter { VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -22,8 +22,6 @@ VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, backend_context_(std::move(backend_context)), session_(session), wait_(this) { - ASSERT_IS_GPU_THREAD; - FXL_DCHECK(session_); zx::vmo exported_vmo; @@ -55,7 +53,6 @@ VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, } VulkanSurface::~VulkanSurface() { - ASSERT_IS_GPU_THREAD; if (async_) { wait_.Cancel(async_); wait_.set_object(ZX_HANDLE_INVALID); @@ -325,7 +322,6 @@ bool VulkanSurface::PushSessionImageSetupOps(scenic_lib::Session* session, } scenic_lib::Image* VulkanSurface::GetImage() { - ASSERT_IS_GPU_THREAD; if (!valid_) { return 0; } @@ -333,7 +329,6 @@ scenic_lib::Image* VulkanSurface::GetImage() { } sk_sp VulkanSurface::GetSkiaSurface() const { - ASSERT_IS_GPU_THREAD; return valid_ ? sk_surface_ : nullptr; } @@ -358,7 +353,6 @@ bool VulkanSurface::FlushSessionAcquireAndReleaseEvents() { void VulkanSurface::SignalWritesFinished( std::function on_writes_committed) { - ASSERT_IS_GPU_THREAD; FXL_DCHECK(on_writes_committed); if (!valid_) { @@ -374,8 +368,6 @@ void VulkanSurface::SignalWritesFinished( } void VulkanSurface::Reset() { - ASSERT_IS_GPU_THREAD; - if (acquire_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK || release_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK) { valid_ = false; @@ -410,10 +402,10 @@ void VulkanSurface::Reset() { } } -async_wait_result_t VulkanSurface::OnHandleReady(async_t* async, - zx_status_t status, - const zx_packet_signal_t* signal) { - ASSERT_IS_GPU_THREAD; +async_wait_result_t VulkanSurface::OnHandleReady( + async_t* async, + zx_status_t status, + const zx_packet_signal_t* signal) { if (status != ZX_OK) return ASYNC_WAIT_FINISHED; FXL_DCHECK(signal->observed & ZX_EVENT_SIGNALED); @@ -421,4 +413,4 @@ async_wait_result_t VulkanSurface::OnHandleReady(async_t* async, return ASYNC_WAIT_AGAIN; } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface.h b/content_handler/vulkan_surface.h index 41a807af81f9c..7add6b05bb8cc 100644 --- a/content_handler/vulkan_surface.h +++ b/content_handler/vulkan_surface.h @@ -20,9 +20,10 @@ #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" -namespace flutter_runner { +namespace flutter { -class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface { +class VulkanSurface final + : public flow::SceneUpdateContext::SurfaceProducerSurface { public: VulkanSurface(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -32,12 +33,16 @@ class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface { ~VulkanSurface() override; + // |flow::SceneUpdateContext::SurfaceProducerSurface| size_t AdvanceAndGetAge() override; + // |flow::SceneUpdateContext::SurfaceProducerSurface| bool FlushSessionAcquireAndReleaseEvents() override; + // |flow::SceneUpdateContext::SurfaceProducerSurface| bool IsValid() const override; + // |flow::SceneUpdateContext::SurfaceProducerSurface| SkISize GetSize() const override; // Note: It is safe for the caller to collect the surface in the @@ -115,4 +120,4 @@ class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface { FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurface); }; -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface_pool.cc b/content_handler/vulkan_surface_pool.cc index af23ef711b7ad..93d14c2ddbff7 100644 --- a/content_handler/vulkan_surface_pool.cc +++ b/content_handler/vulkan_surface_pool.cc @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "vulkan_surface_pool.h" + #include -#include "flutter/content_handler/vulkan_surface_pool.h" #include "flutter/glue/trace_event.h" #include "third_party/skia/include/gpu/GrContext.h" -namespace flutter_runner { +namespace flutter { VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -177,4 +178,4 @@ void VulkanSurfacePool::TraceStats() { trace_surfaces_reused_ = 0; } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface_pool.h b/content_handler/vulkan_surface_pool.h index 52dd3ed6aa417..4900816762910 100644 --- a/content_handler/vulkan_surface_pool.h +++ b/content_handler/vulkan_surface_pool.h @@ -6,12 +6,13 @@ #include #include -#include "flutter/content_handler/vulkan_surface.h" + #include "lib/fxl/macros.h" +#include "vulkan_surface.h" -namespace flutter_runner { +namespace flutter { -class VulkanSurfacePool { +class VulkanSurfacePool final { public: static const size_t kMaxSurfacesOfSameSize = 3; static const size_t kMaxSurfaceAge = 3; @@ -74,4 +75,4 @@ class VulkanSurfacePool { FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfacePool); }; -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface_producer.cc b/content_handler/vulkan_surface_producer.cc index 6f605c109b7df..ff8a9ab9d1f4a 100644 --- a/content_handler/vulkan_surface_producer.cc +++ b/content_handler/vulkan_surface_producer.cc @@ -2,17 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/content_handler/vulkan_surface_producer.h" +#include "vulkan_surface_producer.h" #include #include #include + #include "flutter/glue/trace_event.h" #include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/vk/GrVkTypes.h" -namespace flutter_runner { +namespace flutter { VulkanSurfaceProducer::VulkanSurfaceProducer( scenic_lib::Session* mozart_session) { @@ -42,7 +43,7 @@ bool VulkanSurfaceProducer::Initialize(scenic_lib::Session* mozart_session) { VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, }; application_ = std::make_unique( - *vk_, "FlutterContentHandler", std::move(extensions)); + *vk_, "FlutterApplicationRunner", std::move(extensions)); if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) { // Make certain the application instance was created and it setup the @@ -200,4 +201,4 @@ void VulkanSurfaceProducer::SubmitSurface( surface_pool_->SubmitSurface(std::move(surface)); } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface_producer.h b/content_handler/vulkan_surface_producer.h index 2338a8a6ba709..15c4419e8cde7 100644 --- a/content_handler/vulkan_surface_producer.h +++ b/content_handler/vulkan_surface_producer.h @@ -2,11 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ -#define FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ +#pragma once -#include "flutter/content_handler/vulkan_surface.h" -#include "flutter/content_handler/vulkan_surface_pool.h" #include "flutter/flow/scene_update_context.h" #include "flutter/vulkan/vulkan_application.h" #include "flutter/vulkan/vulkan_device.h" @@ -17,11 +14,14 @@ #include "lib/ui/scenic/client/resources.h" #include "lib/ui/scenic/client/session.h" #include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" +#include "vulkan_surface.h" +#include "vulkan_surface_pool.h" -namespace flutter_runner { +namespace flutter { -class VulkanSurfaceProducer : public flow::SceneUpdateContext::SurfaceProducer, - public vulkan::VulkanProvider { +class VulkanSurfaceProducer final + : public flow::SceneUpdateContext::SurfaceProducer, + public vulkan::VulkanProvider { public: VulkanSurfaceProducer(scenic_lib::Session* mozart_session); @@ -74,6 +74,4 @@ class VulkanSurfaceProducer : public flow::SceneUpdateContext::SurfaceProducer, FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfaceProducer); }; -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ +} // namespace flutter diff --git a/flow/BUILD.gn b/flow/BUILD.gn index e6a6411a6c1da..07c5d4e5d4e7b 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -48,11 +48,12 @@ source_set("flow") { "matrix_decomposition.h", "paint_utils.cc", "paint_utils.h", - "process_info.h", "raster_cache.cc", "raster_cache.h", "raster_cache_key.cc", "raster_cache_key.h", + "skia_gpu_object.cc", + "skia_gpu_object.h", "texture.cc", "texture.h", ] @@ -61,12 +62,11 @@ source_set("flow") { "//garnet/public/lib/fxl", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] deps = [ "$flutter_root/common", + "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/synchronization", "//third_party/skia", @@ -103,8 +103,8 @@ executable("flow_unittests") { deps = [ ":flow", - "//third_party/dart/runtime:libdart_jit", # for tracing "$flutter_root/testing", + "//third_party/dart/runtime:libdart_jit", # for tracing "//third_party/skia", ] } diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index e0d17229e7981..53659103be9f1 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -4,12 +4,12 @@ #include "flutter/flow/compositor_context.h" +#include "flutter/flow/layers/layer_tree.h" #include "third_party/skia/include/core/SkCanvas.h" namespace flow { -CompositorContext::CompositorContext(std::unique_ptr info) - : process_info_(std::move(info)) {} +CompositorContext::CompositorContext() = default; CompositorContext::~CompositorContext() = default; @@ -18,10 +18,6 @@ void CompositorContext::BeginFrame(ScopedFrame& frame, if (enable_instrumentation) { frame_count_.Increment(); frame_time_.Start(); - - if (process_info_ && process_info_->SampleNow()) { - memory_usage_.Add(process_info_->GetResidentMemorySize()); - } } } @@ -33,11 +29,12 @@ void CompositorContext::EndFrame(ScopedFrame& frame, } } -CompositorContext::ScopedFrame CompositorContext::AcquireFrame( +std::unique_ptr CompositorContext::AcquireFrame( GrContext* gr_context, SkCanvas* canvas, bool instrumentation_enabled) { - return ScopedFrame(*this, gr_context, canvas, instrumentation_enabled); + return std::make_unique(*this, gr_context, canvas, + instrumentation_enabled); } CompositorContext::ScopedFrame::ScopedFrame(CompositorContext& context, @@ -51,18 +48,23 @@ CompositorContext::ScopedFrame::ScopedFrame(CompositorContext& context, context_.BeginFrame(*this, instrumentation_enabled_); } -CompositorContext::ScopedFrame::ScopedFrame(ScopedFrame&& frame) = default; - CompositorContext::ScopedFrame::~ScopedFrame() { context_.EndFrame(*this, instrumentation_enabled_); } +bool CompositorContext::ScopedFrame::Raster(flow::LayerTree& layer_tree, + bool ignore_raster_cache) { + layer_tree.Preroll(*this, ignore_raster_cache); + layer_tree.Paint(*this); + return true; +} + void CompositorContext::OnGrContextCreated() { - texture_registry_->OnGrContextCreated(); + texture_registry_.OnGrContextCreated(); } void CompositorContext::OnGrContextDestroyed() { - texture_registry_->OnGrContextDestroyed(); + texture_registry_.OnGrContextDestroyed(); raster_cache_.Clear(); } diff --git a/flow/compositor_context.h b/flow/compositor_context.h index 2d310422747b7..14c2449dbecd0 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -9,7 +9,6 @@ #include #include "flutter/flow/instrumentation.h" -#include "flutter/flow/process_info.h" #include "flutter/flow/raster_cache.h" #include "flutter/flow/texture.h" #include "lib/fxl/macros.h" @@ -18,19 +17,26 @@ namespace flow { +class LayerTree; + class CompositorContext { public: class ScopedFrame { public: + ScopedFrame(CompositorContext& context, + GrContext* gr_context, + SkCanvas* canvas, + bool instrumentation_enabled); + + virtual ~ScopedFrame(); + SkCanvas* canvas() { return canvas_; } CompositorContext& context() const { return context_; } GrContext* gr_context() const { return gr_context_; } - ScopedFrame(ScopedFrame&& frame); - - ~ScopedFrame(); + virtual bool Raster(LayerTree& layer_tree, bool ignore_raster_cache); private: CompositorContext& context_; @@ -38,23 +44,17 @@ class CompositorContext { SkCanvas* canvas_; const bool instrumentation_enabled_; - ScopedFrame(CompositorContext& context, - GrContext* gr_context, - SkCanvas* canvas, - bool instrumentation_enabled); - - friend class CompositorContext; - FXL_DISALLOW_COPY_AND_ASSIGN(ScopedFrame); }; - CompositorContext(std::unique_ptr info); + CompositorContext(); - ~CompositorContext(); + virtual ~CompositorContext(); - ScopedFrame AcquireFrame(GrContext* gr_context, - SkCanvas* canvas, - bool instrumentation_enabled = true); + virtual std::unique_ptr AcquireFrame( + GrContext* gr_context, + SkCanvas* canvas, + bool instrumentation_enabled); void OnGrContextCreated(); @@ -62,7 +62,7 @@ class CompositorContext { RasterCache& raster_cache() { return raster_cache_; } - TextureRegistry& texture_registry() { return *texture_registry_; } + TextureRegistry& texture_registry() { return texture_registry_; } const Counter& frame_count() const { return frame_count_; } @@ -70,20 +70,12 @@ class CompositorContext { Stopwatch& engine_time() { return engine_time_; } - const CounterValues& memory_usage() const { return memory_usage_; } - - void SetTextureRegistry(TextureRegistry* textureRegistry) { - texture_registry_ = textureRegistry; - } - private: RasterCache raster_cache_; - TextureRegistry* texture_registry_; - std::unique_ptr process_info_; + TextureRegistry texture_registry_; Counter frame_count_; Stopwatch frame_time_; Stopwatch engine_time_; - CounterValues memory_usage_; void BeginFrame(ScopedFrame& frame, bool enable_instrumentation); diff --git a/flow/debug_print.cc b/flow/debug_print.cc index 0aa5b4b3b7d2d..3311b9c2b43e3 100644 --- a/flow/debug_print.cc +++ b/flow/debug_print.cc @@ -80,3 +80,8 @@ std::ostream& operator<<(std::ostream& os, const flow::RasterCacheKey& k) { ; return os; } + +std::ostream& operator<<(std::ostream& os, const SkISize& size) { + os << size.width() << ", " << size.height(); + return os; +} diff --git a/flow/debug_print.h b/flow/debug_print.h index ca5973eeb0977..78a28fe38562d 100644 --- a/flow/debug_print.h +++ b/flow/debug_print.h @@ -15,14 +15,15 @@ #define DEF_PRINTER(x) std::ostream& operator<<(std::ostream&, const x&); -DEF_PRINTER(flow::RasterCacheKey); DEF_PRINTER(flow::MatrixDecomposition); +DEF_PRINTER(flow::RasterCacheKey); +DEF_PRINTER(SkISize); DEF_PRINTER(SkMatrix); DEF_PRINTER(SkMatrix44); -DEF_PRINTER(SkVector3); -DEF_PRINTER(SkVector4); +DEF_PRINTER(SkPoint); DEF_PRINTER(SkRect); DEF_PRINTER(SkRRect); -DEF_PRINTER(SkPoint); +DEF_PRINTER(SkVector3); +DEF_PRINTER(SkVector4); #endif // FLUTTER_FLOW_DEBUG_PRINT_H_ diff --git a/flow/export_node.cc b/flow/export_node.cc index a130c426a75bf..27ab34030ca42 100644 --- a/flow/export_node.cc +++ b/flow/export_node.cc @@ -4,28 +4,27 @@ #include "flutter/flow/export_node.h" -#include "flutter/common/threads.h" #include "lib/fxl/functional/make_copyable.h" namespace flow { ExportNodeHolder::ExportNodeHolder( + fxl::RefPtr gpu_task_runner, fxl::RefPtr export_token_handle) - : export_node_(std::make_unique(export_token_handle)) { - ASSERT_IS_UI_THREAD; + : gpu_task_runner_(std::move(gpu_task_runner)), + export_node_(std::make_unique(export_token_handle)) { + FXL_DCHECK(gpu_task_runner_); } void ExportNodeHolder::Bind(SceneUpdateContext& context, scenic_lib::ContainerNode& container, const SkPoint& offset, bool hit_testable) { - ASSERT_IS_GPU_THREAD; export_node_->Bind(context, container, offset, hit_testable); } ExportNodeHolder::~ExportNodeHolder() { - ASSERT_IS_UI_THREAD; - blink::Threads::Gpu()->PostTask( + gpu_task_runner_->PostTask( fxl::MakeCopyable([export_node = std::move(export_node_)]() { export_node->Dispose(true); })); @@ -44,8 +43,6 @@ void ExportNode::Bind(SceneUpdateContext& context, scenic_lib::ContainerNode& container, const SkPoint& offset, bool hit_testable) { - ASSERT_IS_GPU_THREAD; - if (export_token_) { // Happens first time we bind. node_.reset(new scenic_lib::EntityNode(container.session())); @@ -67,8 +64,6 @@ void ExportNode::Bind(SceneUpdateContext& context, } void ExportNode::Dispose(bool remove_from_scene_update_context) { - ASSERT_IS_GPU_THREAD; - // If scene_update_context_ is set, then we should still have a node left to // dereference. // If scene_update_context_ is null, then either: diff --git a/flow/export_node.h b/flow/export_node.h index 24f94fcebf20f..e6a11175e561e 100644 --- a/flow/export_node.h +++ b/flow/export_node.h @@ -15,6 +15,7 @@ #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_counted.h" #include "lib/ui/scenic/client/resources.h" +#include "third_party/flutter/fml/task_runner.h" #include "third_party/skia/include/core/SkPoint.h" namespace flow { @@ -24,7 +25,8 @@ namespace flow { // held by the ExportNode. class ExportNodeHolder : public fxl::RefCountedThreadSafe { public: - ExportNodeHolder(fxl::RefPtr export_token_handle); + ExportNodeHolder(fxl::RefPtr gpu_task_runner, + fxl::RefPtr export_token_handle); ~ExportNodeHolder(); // Calls Bind() on the wrapped ExportNode. @@ -36,6 +38,7 @@ class ExportNodeHolder : public fxl::RefCountedThreadSafe { ExportNode* export_node() { return export_node_.get(); } private: + fxl::RefPtr gpu_task_runner_; std::unique_ptr export_node_; FRIEND_MAKE_REF_COUNTED(ExportNodeHolder); diff --git a/flow/layers/default_layer_builder.cc b/flow/layers/default_layer_builder.cc index a33b0eaa681b7..ca228a7d58f76 100644 --- a/flow/layers/default_layer_builder.cc +++ b/flow/layers/default_layer_builder.cc @@ -137,20 +137,20 @@ void DefaultLayerBuilder::PushPerformanceOverlay(uint64_t enabled_options, } void DefaultLayerBuilder::PushPicture(const SkPoint& offset, - sk_sp picture, + SkiaGPUObject picture, bool picture_is_complex, bool picture_will_change) { if (!current_layer_) { return; } - SkRect pictureRect = picture->cullRect(); + SkRect pictureRect = picture.get()->cullRect(); pictureRect.offset(offset.x(), offset.y()); if (!SkRect::Intersects(pictureRect, cull_rects_.top())) { return; } auto layer = std::make_unique(); layer->set_offset(offset); - layer->set_picture(picture); + layer->set_picture(std::move(picture)); layer->set_is_complex(picture_is_complex); layer->set_will_change(picture_will_change); current_layer_->Add(std::move(layer)); diff --git a/flow/layers/default_layer_builder.h b/flow/layers/default_layer_builder.h index a62ec46714d21..cadd173ab5a84 100644 --- a/flow/layers/default_layer_builder.h +++ b/flow/layers/default_layer_builder.h @@ -59,7 +59,7 @@ class DefaultLayerBuilder final : public LayerBuilder { // |flow::LayerBuilder| void PushPicture(const SkPoint& offset, - sk_sp picture, + SkiaGPUObject picture, bool picture_is_complex, bool picture_will_change) override; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index d0ef1990ab4f2..cf7ad71c36fae 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -44,9 +44,6 @@ class Layer { virtual ~Layer(); struct PrerollContext { -#if defined(OS_FUCHSIA) - gfx::Metrics* metrics = nullptr; -#endif RasterCache* raster_cache; GrContext* gr_context; SkColorSpace* dst_color_space; @@ -59,7 +56,6 @@ class Layer { SkCanvas& canvas; const Stopwatch& frame_time; const Stopwatch& engine_time; - const CounterValues& memory_usage; TextureRegistry& texture_registry; const bool checkerboard_offscreen_layers; }; diff --git a/flow/layers/layer_builder.h b/flow/layers/layer_builder.h index 91ae13974a23b..a29e959514428 100644 --- a/flow/layers/layer_builder.h +++ b/flow/layers/layer_builder.h @@ -8,6 +8,7 @@ #include #include "flutter/flow/layers/layer.h" +#include "flutter/flow/skia_gpu_object.h" #include "garnet/public/lib/fxl/macros.h" #include "third_party/skia/include/core/SkBlendMode.h" #include "third_party/skia/include/core/SkColor.h" @@ -57,7 +58,7 @@ class LayerBuilder { const SkRect& rect) = 0; virtual void PushPicture(const SkPoint& offset, - sk_sp picture, + SkiaGPUObject picture, bool picture_is_complex, bool picture_will_change) = 0; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index fde2fc4bf0866..d9fb374194688 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -17,43 +17,18 @@ LayerTree::LayerTree() LayerTree::~LayerTree() = default; -void LayerTree::Raster(CompositorContext::ScopedFrame& frame, -#if defined(OS_FUCHSIA) - gfx::Metrics* metrics, -#endif - bool ignore_raster_cache) { -#if defined(OS_FUCHSIA) - FXL_DCHECK(metrics); -#endif - Preroll(frame, -#if defined(OS_FUCHSIA) - metrics, -#endif - ignore_raster_cache); - Paint(frame); -} - void LayerTree::Preroll(CompositorContext::ScopedFrame& frame, -#if defined(OS_FUCHSIA) - gfx::Metrics* metrics, -#endif bool ignore_raster_cache) { -#if defined(OS_FUCHSIA) - FXL_DCHECK(metrics); -#endif TRACE_EVENT0("flutter", "LayerTree::Preroll"); SkColorSpace* color_space = frame.canvas() ? frame.canvas()->imageInfo().colorSpace() : nullptr; frame.context().raster_cache().SetCheckboardCacheImages( checkerboard_raster_cache_images_); Layer::PrerollContext context = { -#if defined(OS_FUCHSIA) - metrics, -#endif - ignore_raster_cache ? nullptr : &frame.context().raster_cache(), - frame.gr_context(), - color_space, - SkRect::MakeEmpty(), + ignore_raster_cache ? nullptr : &frame.context().raster_cache(), + frame.gr_context(), + color_space, + SkRect::MakeEmpty(), }; root_layer_->Preroll(&context, SkMatrix::I()); @@ -63,9 +38,12 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame, void LayerTree::UpdateScene(SceneUpdateContext& context, scenic_lib::ContainerNode& container) { TRACE_EVENT0("flutter", "LayerTree::UpdateScene"); - - SceneUpdateContext::Transform transform(context, 1.f / device_pixel_ratio_, - 1.f / device_pixel_ratio_, 1.f); + const auto& metrics = context.metrics(); + SceneUpdateContext::Transform transform(context, // context + 1.0f / metrics->scale_x, // X + 1.0f / metrics->scale_y, // Y + 1.0f / metrics->scale_z // Z + ); SceneUpdateContext::Frame frame( context, SkRRect::MakeRect( @@ -82,12 +60,13 @@ void LayerTree::UpdateScene(SceneUpdateContext& context, #endif void LayerTree::Paint(CompositorContext::ScopedFrame& frame) const { - Layer::PaintContext context = {*frame.canvas(), - frame.context().frame_time(), - frame.context().engine_time(), - frame.context().memory_usage(), - frame.context().texture_registry(), - checkerboard_offscreen_layers_}; + Layer::PaintContext context = { + *frame.canvas(), // + frame.context().frame_time(), // + frame.context().engine_time(), // + frame.context().texture_registry(), // + checkerboard_offscreen_layers_ // + }; TRACE_EVENT0("flutter", "LayerTree::Paint"); if (root_layer_->needs_painting()) diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index 5ddebd088de9e..25a8e072cfa21 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -13,9 +13,6 @@ #include "flutter/flow/layers/layer.h" #include "lib/fxl/macros.h" #include "lib/fxl/time/time_delta.h" -#if defined(OS_FUCHSIA) -#include -#endif #include "third_party/skia/include/core/SkSize.h" namespace flow { @@ -26,24 +23,10 @@ class LayerTree { ~LayerTree(); - // Raster includes both Preroll and Paint. - void Raster(CompositorContext::ScopedFrame& frame, -#if defined(OS_FUCHSIA) - gfx::Metrics* metrics, -#endif - bool ignore_raster_cache = false); - void Preroll(CompositorContext::ScopedFrame& frame, -#if defined(OS_FUCHSIA) - gfx::Metrics* metrics, -#endif bool ignore_raster_cache = false); #if defined(OS_FUCHSIA) - void set_device_pixel_ratio(float device_pixel_ratio) { - device_pixel_ratio_ = device_pixel_ratio; - } - void UpdateScene(SceneUpdateContext& context, scenic_lib::ContainerNode& container); #endif @@ -93,10 +76,6 @@ class LayerTree { bool checkerboard_raster_cache_images_; bool checkerboard_offscreen_layers_; -#if defined(OS_FUCHSIA) - float device_pixel_ratio_ = 1.f; -#endif - FXL_DISALLOW_COPY_AND_ASSIGN(LayerTree); }; diff --git a/flow/layers/performance_overlay_layer.cc b/flow/layers/performance_overlay_layer.cc index cc55500115a08..7d871af33b94f 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -57,34 +57,6 @@ void VisualizeStopWatch(SkCanvas& canvas, } } -void VisualizeCounterValuesBytes(SkCanvas& canvas, - const CounterValues& counter_values, - SkScalar x, - SkScalar y, - SkScalar width, - SkScalar height, - bool show_graph, - bool show_labels, - const std::string& label_prefix) { - const int label_x = 8; // distance from x - const int label_y = -10; // distance from y+height - - if (show_graph) { - SkRect visualization_rect = SkRect::MakeXYWH(x, y, width, height); - counter_values.Visualize(canvas, visualization_rect); - } - - auto current_usage = counter_values.GetCurrentValue(); - - if (show_labels && current_usage > 0) { - std::stringstream stream; - stream.setf(std::ios::fixed | std::ios::showpoint); - stream << std::setprecision(2); - stream << label_prefix << " " << current_usage * 1e-6 << " MB"; - DrawStatisticsText(canvas, stream.str(), x + label_x, y + height + label_y); - } -} - } // namespace PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t options) @@ -111,11 +83,6 @@ void PerformanceOverlayLayer::Paint(PaintContext& context) const { VisualizeStopWatch(context.canvas, context.engine_time, x, y + height, width, height - padding, options_ & kVisualizeEngineStatistics, options_ & kDisplayEngineStatistics, "UI"); - - VisualizeCounterValuesBytes( - context.canvas, context.memory_usage, x, y + (2 * height), width, - height - padding, options_ & kVisualizeMemoryStatistics, - options_ & kDisplayMemoryStatistics, "Memory (Resident)"); } } // namespace flow diff --git a/flow/layers/performance_overlay_layer.h b/flow/layers/performance_overlay_layer.h index e7c3ac530a02a..77448107147a4 100644 --- a/flow/layers/performance_overlay_layer.h +++ b/flow/layers/performance_overlay_layer.h @@ -14,8 +14,6 @@ const int kDisplayRasterizerStatistics = 1 << 0; const int kVisualizeRasterizerStatistics = 1 << 1; const int kDisplayEngineStatistics = 1 << 2; const int kVisualizeEngineStatistics = 1 << 3; -const int kDisplayMemoryStatistics = 1 << 4; -const int kVisualizeMemoryStatistics = 1 << 5; class PerformanceOverlayLayer : public Layer { public: diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index 4a99d7d07f75e..552ca0443bd80 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -4,39 +4,30 @@ #include "flutter/flow/layers/picture_layer.h" -#include "flutter/common/threads.h" #include "lib/fxl/logging.h" namespace flow { PictureLayer::PictureLayer() = default; -PictureLayer::~PictureLayer() { - // The picture may contain references to textures that are associated - // with the IO thread's context. - SkPicture* picture = picture_.release(); - if (picture) { - blink::Threads::IO()->PostTask([picture]() { picture->unref(); }); - } -} +PictureLayer::~PictureLayer() = default; void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + SkPicture* sk_picture = picture(); + if (auto cache = context->raster_cache) { raster_cache_result_ = cache->GetPrerolledImage( - context->gr_context, picture_.get(), matrix, context->dst_color_space, -#if defined(OS_FUCHSIA) - context->metrics, -#endif + context->gr_context, sk_picture, matrix, context->dst_color_space, is_complex_, will_change_); } - SkRect bounds = picture_->cullRect().makeOffset(offset_.x(), offset_.y()); + SkRect bounds = sk_picture->cullRect().makeOffset(offset_.x(), offset_.y()); set_paint_bounds(bounds); } void PictureLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "PictureLayer::Paint"); - FXL_DCHECK(picture_); + FXL_DCHECK(picture_.get()); FXL_DCHECK(needs_painting()); SkAutoCanvasRestore save(&context.canvas, true); @@ -53,7 +44,7 @@ void PictureLayer::Paint(PaintContext& context) const { SkCanvas::kStrict_SrcRectConstraint // source constraint ); } else { - context.canvas.drawPicture(picture_.get()); + context.canvas.drawPicture(picture()); } } diff --git a/flow/layers/picture_layer.h b/flow/layers/picture_layer.h index 191ef9d7097a2..c67929b7cb455 100644 --- a/flow/layers/picture_layer.h +++ b/flow/layers/picture_layer.h @@ -5,8 +5,11 @@ #ifndef FLUTTER_FLOW_LAYERS_PICTURE_LAYER_H_ #define FLUTTER_FLOW_LAYERS_PICTURE_LAYER_H_ +#include + #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" +#include "flutter/flow/skia_gpu_object.h" namespace flow { @@ -16,12 +19,14 @@ class PictureLayer : public Layer { ~PictureLayer() override; void set_offset(const SkPoint& offset) { offset_ = offset; } - void set_picture(sk_sp picture) { picture_ = std::move(picture); } + void set_picture(SkiaGPUObject picture) { + picture_ = std::move(picture); + } void set_is_complex(bool value) { is_complex_ = value; } void set_will_change(bool value) { will_change_ = value; } - SkPicture* picture() const { return picture_.get(); } + SkPicture* picture() const { return picture_.get().get(); } void Preroll(PrerollContext* frame, const SkMatrix& matrix) override; @@ -29,7 +34,9 @@ class PictureLayer : public Layer { private: SkPoint offset_; - sk_sp picture_; + // Even though pictures themselves are not GPU resources, they may reference + // images that have a reference to a GPU resource. + SkiaGPUObject picture_; bool is_complex_ = false; bool will_change_ = false; RasterCacheResult raster_cache_result_; diff --git a/flow/process_info.h b/flow/process_info.h deleted file mode 100644 index 6623fe7257396..0000000000000 --- a/flow/process_info.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2016 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_FLOW_PROCESS_INFO_H_ -#define FLUTTER_FLOW_PROCESS_INFO_H_ - -#include "lib/fxl/macros.h" - -namespace flow { - -/// The CompositorContext attempts to collect information from the process for -/// instrumentation purposes. The compositor does not have the platform -/// specific capabilities to collect this information on its own. The platform -/// can choose to provide this information however. -class ProcessInfo { - public: - virtual ~ProcessInfo() = default; - - virtual bool SampleNow() = 0; - - /// Virtual memory size in bytes. - virtual size_t GetVirtualMemorySize() = 0; - - /// Resident memory size in bytes. - virtual size_t GetResidentMemorySize() = 0; -}; - -} // namespace flow - -#endif // FLUTTER_FLOW_PROCESS_INFO_H_ diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index aa9fad0e281de..11a86729b489b 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -6,7 +6,6 @@ #include -#include "flutter/common/threads.h" #include "flutter/flow/paint_utils.h" #include "flutter/glue/trace_event.h" #include "lib/fxl/logging.h" @@ -73,9 +72,6 @@ RasterCacheResult RasterizePicture(SkPicture* picture, GrContext* context, const MatrixDecomposition& matrix, SkColorSpace* dst_color_space, -#if defined(OS_FUCHSIA) - gfx::Metrics* metrics, -#endif bool checkerboard) { TRACE_EVENT0("flutter", "RasterCachePopulate"); @@ -83,17 +79,9 @@ RasterCacheResult RasterizePicture(SkPicture* picture, const SkRect logical_rect = picture->cullRect(); -#if defined(OS_FUCHSIA) - float metrics_scale_x = metrics->scale_x; - float metrics_scale_y = metrics->scale_y; -#else - float metrics_scale_x = 1.f; - float metrics_scale_y = 1.f; -#endif - - const SkRect physical_rect = SkRect::MakeWH( - std::fabs(logical_rect.width() * metrics_scale_x * scale.x()), - std::fabs(logical_rect.height() * metrics_scale_y * scale.y())); + const SkRect physical_rect = + SkRect::MakeWH(std::fabs(logical_rect.width() * scale.x()), + std::fabs(logical_rect.height() * scale.y())); const SkImageInfo image_info = SkImageInfo::MakeN32Premul( std::ceil(physical_rect.width()), // physical width @@ -120,8 +108,7 @@ RasterCacheResult RasterizePicture(SkPicture* picture, } canvas->clear(SK_ColorTRANSPARENT); - canvas->scale(std::abs(scale.x() * metrics_scale_x), - std::abs(scale.y() * metrics_scale_y)); + canvas->scale(std::abs(scale.x()), std::abs(scale.y())); canvas->translate(-logical_rect.left(), -logical_rect.top()); canvas->drawPicture(picture); @@ -153,9 +140,6 @@ RasterCacheResult RasterCache::GetPrerolledImage( SkPicture* picture, const SkMatrix& transformation_matrix, SkColorSpace* dst_color_space, -#if defined(OS_FUCHSIA) - gfx::Metrics* metrics, -#endif bool is_complex, bool will_change) { if (!IsPictureWorthRasterizing(picture, will_change, is_complex)) { @@ -172,11 +156,7 @@ RasterCacheResult RasterCache::GetPrerolledImage( return {}; } - RasterCacheKey cache_key(*picture, -#if defined(OS_FUCHSIA) - metrics->scale_x, metrics->scale_y, -#endif - matrix); + RasterCacheKey cache_key(*picture, matrix); Entry& entry = cache_[cache_key]; entry.access_count = ClampSize(entry.access_count + 1, 0, threshold_); @@ -189,9 +169,6 @@ RasterCacheResult RasterCache::GetPrerolledImage( if (!entry.image.is_valid()) { entry.image = RasterizePicture(picture, context, matrix, dst_color_space, -#if defined(OS_FUCHSIA) - metrics, -#endif checkerboard_images_); } diff --git a/flow/raster_cache.h b/flow/raster_cache.h index 31201049b6119..3278eb355b030 100644 --- a/flow/raster_cache.h +++ b/flow/raster_cache.h @@ -12,9 +12,6 @@ #include "flutter/flow/raster_cache_key.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/weak_ptr.h" -#if defined(OS_FUCHSIA) -#include -#endif #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkSize.h" @@ -57,9 +54,6 @@ class RasterCache { SkPicture* picture, const SkMatrix& transformation_matrix, SkColorSpace* dst_color_space, -#if defined(OS_FUCHSIA) - gfx::Metrics* metrics, -#endif bool is_complex, bool will_change); diff --git a/flow/raster_cache_key.h b/flow/raster_cache_key.h index 83df52658c981..1f28ea5320d36 100644 --- a/flow/raster_cache_key.h +++ b/flow/raster_cache_key.h @@ -15,30 +15,15 @@ namespace flow { class RasterCacheKey { public: - RasterCacheKey(const SkPicture& picture, -#if defined(OS_FUCHSIA) - float metrics_scale_x, - float metrics_scale_y, -#endif - const MatrixDecomposition& matrix) + RasterCacheKey(const SkPicture& picture, const MatrixDecomposition& matrix) : picture_id_(picture.uniqueID()), -#if defined(OS_FUCHSIA) - metrics_scale_x_(metrics_scale_x), - metrics_scale_y_(metrics_scale_y), -#endif - scale_key_( - SkISize::Make(matrix.scale().x() * 1e3, matrix.scale().y() * 1e3)) { - } + scale_key_(SkISize::Make(matrix.scale().x() * 1e3, + matrix.scale().y() * 1e3)) {} uint32_t picture_id() const { return picture_id_; } const SkISize& scale_key() const { return scale_key_; } -#if defined(OS_FUCHSIA) - float metrics_scale_x() const { return metrics_scale_x_; } - float metrics_scale_y() const { return metrics_scale_y_; } -#endif - struct Hash { std::size_t operator()(RasterCacheKey const& key) const { return key.picture_id_; @@ -49,11 +34,6 @@ class RasterCacheKey { constexpr bool operator()(const RasterCacheKey& lhs, const RasterCacheKey& rhs) const { return lhs.picture_id_ == rhs.picture_id_ && -#if defined(OS_FUCHSIA) - lhs.metrics_scale_x_ == rhs.metrics_scale_x_ && - - lhs.metrics_scale_y_ == rhs.metrics_scale_y_ && -#endif lhs.scale_key_ == rhs.scale_key_; } }; @@ -63,10 +43,6 @@ class RasterCacheKey { private: uint32_t picture_id_; -#if defined(OS_FUCHSIA) - float metrics_scale_x_; - float metrics_scale_y_; -#endif SkISize scale_key_; }; diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc index 83883c508b4df..b9d6801cc82ee 100644 --- a/flow/scene_update_context.cc +++ b/flow/scene_update_context.cc @@ -4,7 +4,6 @@ #include "flutter/flow/scene_update_context.h" -#include "flutter/common/threads.h" #include "flutter/flow/export_node.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/matrix_decomposition.h" @@ -19,9 +18,7 @@ SceneUpdateContext::SceneUpdateContext(scenic_lib::Session* session, } SceneUpdateContext::~SceneUpdateContext() { - ASSERT_IS_GPU_THREAD; - - // Release Scenic session resources for all ExportNodes. + // Release Mozart session resources for all ExportNodes. for (auto export_node : export_nodes_) { export_node->Dispose(false); } @@ -30,21 +27,16 @@ SceneUpdateContext::~SceneUpdateContext() { void SceneUpdateContext::AddChildScene(ExportNode* export_node, SkPoint offset, bool hit_testable) { - ASSERT_IS_GPU_THREAD; FXL_DCHECK(top_entity_); export_node->Bind(*this, top_entity_->entity_node(), offset, hit_testable); } void SceneUpdateContext::AddExportNode(ExportNode* export_node) { - ASSERT_IS_GPU_THREAD; - export_nodes_.insert(export_node); // Might already have been added. } void SceneUpdateContext::RemoveExportNode(ExportNode* export_node) { - ASSERT_IS_GPU_THREAD; - export_nodes_.erase(export_node); } @@ -195,12 +187,9 @@ SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) { for (auto& task : paint_tasks_) { FXL_DCHECK(task.surface); SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas(); - Layer::PaintContext context = {*canvas, - frame.context().frame_time(), + Layer::PaintContext context = {*canvas, frame.context().frame_time(), frame.context().engine_time(), - frame.context().memory_usage(), - frame.context().texture_registry(), - false}; + frame.context().texture_registry(), false}; canvas->restoreToCount(1); canvas->save(); canvas->clear(task.background_color); diff --git a/flow/skia_gpu_object.cc b/flow/skia_gpu_object.cc new file mode 100644 index 0000000000000..ce2312f921580 --- /dev/null +++ b/flow/skia_gpu_object.cc @@ -0,0 +1,44 @@ +// 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/flow/skia_gpu_object.h" + +#include "flutter/fml/message_loop.h" + +namespace flow { + +SkiaUnrefQueue::SkiaUnrefQueue(fxl::RefPtr task_runner, + fxl::TimeDelta delay) + : task_runner_(std::move(task_runner)), + drain_delay_(delay), + drain_pending_(false) {} + +SkiaUnrefQueue::~SkiaUnrefQueue() { + Drain(); +} + +void SkiaUnrefQueue::Unref(SkRefCnt* object) { + std::lock_guard lock(mutex_); + objects_.push_back(object); + if (!drain_pending_) { + drain_pending_ = true; + task_runner_->PostDelayedTask( + [strong = fxl::Ref(this)]() { strong->Drain(); }, drain_delay_); + } +} + +void SkiaUnrefQueue::Drain() { + std::deque skia_objects; + { + std::lock_guard lock(mutex_); + objects_.swap(skia_objects); + drain_pending_ = false; + } + + for (SkRefCnt* skia_object : skia_objects) { + skia_object->unref(); + } +} + +} // namespace flow diff --git a/flow/skia_gpu_object.h b/flow/skia_gpu_object.h new file mode 100644 index 0000000000000..4711f80c6f4fd --- /dev/null +++ b/flow/skia_gpu_object.h @@ -0,0 +1,88 @@ +// 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_FLOW_SKIA_GPU_OBJECT_H_ +#define FLUTTER_FLOW_SKIA_GPU_OBJECT_H_ + +#include +#include + +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/fml/task_runner.h" +#include "lib/fxl/memory/ref_ptr.h" +#include "third_party/skia/include/core/SkRefCnt.h" + +namespace flow { + +// A queue that holds Skia objects that must be destructed on the the given task +// runner. +class SkiaUnrefQueue : public fxl::RefCountedThreadSafe { + public: + void Unref(SkRefCnt* object); + + // Usually, the drain is called automatically. However, during IO manager + // shutdown (when the platform side reference to the OpenGL context is about + // to go away), we may need to pre-emptively drain the unref queue. It is the + // responsibility of the caller to ensure that no further unrefs are queued + // after this call. + void Drain(); + + private: + const fxl::RefPtr task_runner_; + const fxl::TimeDelta drain_delay_; + std::mutex mutex_; + std::deque objects_; + bool drain_pending_; + + SkiaUnrefQueue(fxl::RefPtr task_runner, + fxl::TimeDelta delay); + + ~SkiaUnrefQueue(); + + FRIEND_REF_COUNTED_THREAD_SAFE(SkiaUnrefQueue); + FRIEND_MAKE_REF_COUNTED(SkiaUnrefQueue); + FXL_DISALLOW_COPY_AND_ASSIGN(SkiaUnrefQueue); +}; + +/// An object whose deallocation needs to be performed on an specific unref +/// queue. The template argument U need to have a call operator that returns +/// that unref queue. +template +class SkiaGPUObject { + public: + using SkiaObjectType = T; + + SkiaGPUObject() = default; + + SkiaGPUObject(sk_sp object, fxl::RefPtr queue) + : object_(std::move(object)), queue_(std::move(queue)) { + FXL_DCHECK(queue_ && object_); + } + + SkiaGPUObject(SkiaGPUObject&&) = default; + + ~SkiaGPUObject() { reset(); } + + SkiaGPUObject& operator=(SkiaGPUObject&&) = default; + + sk_sp get() const { return object_; } + + void reset() { + if (object_) { + queue_->Unref(object_.release()); + } + queue_ = nullptr; + FXL_DCHECK(object_ == nullptr); + } + + private: + sk_sp object_; + fxl::RefPtr queue_; + + FXL_DISALLOW_COPY_AND_ASSIGN(SkiaGPUObject); +}; + +} // namespace flow + +#endif // FLUTTER_FLOW_SKIA_GPU_OBJECT_H_ diff --git a/flow/texture.cc b/flow/texture.cc index 33a48af989477..d5cc3ae228aa7 100644 --- a/flow/texture.cc +++ b/flow/texture.cc @@ -11,36 +11,32 @@ TextureRegistry::TextureRegistry() = default; TextureRegistry::~TextureRegistry() = default; void TextureRegistry::RegisterTexture(std::shared_ptr texture) { - ASSERT_IS_GPU_THREAD mapping_[texture->Id()] = texture; } void TextureRegistry::UnregisterTexture(int64_t id) { - ASSERT_IS_GPU_THREAD mapping_.erase(id); } void TextureRegistry::OnGrContextCreated() { - ASSERT_IS_GPU_THREAD; for (auto& it : mapping_) { it.second->OnGrContextCreated(); } } void TextureRegistry::OnGrContextDestroyed() { - ASSERT_IS_GPU_THREAD; for (auto& it : mapping_) { it.second->OnGrContextDestroyed(); } } std::shared_ptr TextureRegistry::GetTexture(int64_t id) { - ASSERT_IS_GPU_THREAD auto it = mapping_.find(id); return it != mapping_.end() ? it->second : nullptr; } Texture::Texture(int64_t id) : id_(id) {} + Texture::~Texture() = default; } // namespace flow diff --git a/flow/texture.h b/flow/texture.h index a602a6b45b5b4..f5e4430834084 100644 --- a/flow/texture.h +++ b/flow/texture.h @@ -6,7 +6,7 @@ #define FLUTTER_FLOW_TEXTURE_H_ #include -#include "flutter/common/threads.h" + #include "lib/fxl/synchronization/waitable_event.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -29,6 +29,9 @@ class Texture { // Called from GPU thread. virtual void OnGrContextDestroyed() = 0; + // Called on GPU thread. + virtual void MarkNewFrameAvailable() = 0; + int64_t Id() { return id_; } private: diff --git a/fml/BUILD.gn b/fml/BUILD.gn index 6dabcb446c912..ffbf949cc0957 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -4,9 +4,12 @@ source_set("fml") { sources = [ + "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 +17,9 @@ source_set("fml") { "message_loop.h", "message_loop_impl.cc", "message_loop_impl.h", + "native_library.h", + "paths.cc", "paths.h", - "task_observer.h", "task_runner.cc", "task_runner.h", "thread.cc", @@ -23,6 +27,9 @@ source_set("fml") { "thread_local.h", "trace_event.cc", "trace_event.h", + "unique_fd.cc", + "unique_fd.h", + "unique_object.h", ] deps = [ @@ -95,16 +102,25 @@ source_set("fml") { ] } + if (is_fuchsia) { + sources += [ "platform/fuchsia/paths_fuchsia.cc" ] + } + if (is_win) { sources += [ + "platform/win/file_win.cc", "platform/win/mapping_win.cc", "platform/win/message_loop_win.cc", "platform/win/message_loop_win.h", + "platform/win/native_library_win.cc", "platform/win/paths_win.cc", + "platform/win/wstring_conversion.h", ] } else { sources += [ + "platform/posix/file_posix.cc", "platform/posix/mapping_posix.cc", + "platform/posix/native_library_posix.cc", ] } } diff --git a/fml/file.h b/fml/file.h new file mode 100644 index 0000000000000..2327b2eef831e --- /dev/null +++ b/fml/file.h @@ -0,0 +1,35 @@ +// 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 "flutter/fml/unique_fd.h" +#include "lib/fxl/macros.h" + +namespace fml { + +enum class OpenPermission { + kRead = 1, + kWrite = 1 << 1, + kReadWrite = kRead | kWrite, + kExecute, +}; + +fml::UniqueFD OpenFile(const char* path, + OpenPermission permission, + bool is_directory = false); + +fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory, + const char* path, + OpenPermission permission, + bool is_directory = false); + +fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor); + +bool IsDirectory(const fml::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..00e9685dd6b0c 100644 --- a/fml/mapping.h +++ b/fml/mapping.h @@ -7,14 +7,10 @@ #include #include +#include +#include "flutter/fml//unique_fd.h" #include "lib/fxl/build_config.h" - -#if OS_WIN -#include -#endif - -#include "lib/fxl/files/unique_fd.h" #include "lib/fxl/macros.h" namespace fml { @@ -39,12 +35,9 @@ 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); -#endif + FileMapping(const fml::UniqueFD& fd, bool executable = false); ~FileMapping() override; @@ -53,16 +46,32 @@ class FileMapping : public Mapping { const uint8_t* GetMapping() const override; private: - size_t size_; - uint8_t* mapping_; + size_t size_ = 0; + uint8_t* mapping_ = nullptr; #if OS_WIN - HANDLE mapping_handle_; + fml::UniqueFD mapping_handle_; #endif 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..f22e9d1cfaf06 --- /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 FLUTTER_FML_MEMORY_THREAD_CHECKER_H_ +#define FLUTTER_FML_MEMORY_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 // FLUTTER_FML_MEMORY_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.h b/fml/native_library.h new file mode 100644 index 0000000000000..7e48ed6d3a3ff --- /dev/null +++ b/fml/native_library.h @@ -0,0 +1,52 @@ +// 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_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" + +#if OS_WIN + +#include + +#endif // OS_WIN + +namespace fml { +class NativeLibrary : public fxl::RefCountedThreadSafe { + public: +#if OS_WIN + using Handle = HMODULE; +#else // OS_WIN + using Handle = void*; +#endif // OS_WIN + + static fxl::RefPtr Create(const char* path); + + static fxl::RefPtr CreateForCurrentProcess(); + + const uint8_t* ResolveSymbol(const char* symbol); + + private: + Handle handle_ = nullptr; + bool close_handle_ = true; + + NativeLibrary(const char* path); + + NativeLibrary(Handle handle, bool close_handle); + + ~NativeLibrary(); + + Handle GetHandle() const; + + FXL_DISALLOW_COPY_AND_ASSIGN(NativeLibrary); + FRIEND_REF_COUNTED_THREAD_SAFE(NativeLibrary); + FRIEND_MAKE_REF_COUNTED(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..9b06b6847f415 --- /dev/null +++ b/fml/paths.cc @@ -0,0 +1,31 @@ +// 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" + +#include "lib/fxl/build_config.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) { +#if OS_WIN + stream << "\\"; +#else // OS_WIN + stream << "/"; +#endif // OS_WIN + } + } + 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/android/message_loop_android.h b/fml/platform/android/message_loop_android.h index e6d04e8253401..19c1eafe79845 100644 --- a/fml/platform/android/message_loop_android.h +++ b/fml/platform/android/message_loop_android.h @@ -10,7 +10,7 @@ #include #include "flutter/fml/message_loop_impl.h" -#include "lib/fxl/files/unique_fd.h" +#include "flutter/fml/unique_fd.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/unique_object.h" @@ -24,8 +24,8 @@ struct UniqueLooperTraits { class MessageLoopAndroid : public MessageLoopImpl { private: - fxl::UniqueObject looper_; - fxl::UniqueFD timer_fd_; + fml::UniqueObject looper_; + fml::UniqueFD timer_fd_; bool running_; MessageLoopAndroid(); 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/linux/message_loop_linux.h b/fml/platform/linux/message_loop_linux.h index 51dc690ce887b..ba5e902d4ac89 100644 --- a/fml/platform/linux/message_loop_linux.h +++ b/fml/platform/linux/message_loop_linux.h @@ -8,15 +8,15 @@ #include #include "flutter/fml/message_loop_impl.h" -#include "lib/fxl/files/unique_fd.h" +#include "flutter/fml/unique_fd.h" #include "lib/fxl/macros.h" namespace fml { class MessageLoopLinux : public MessageLoopImpl { private: - fxl::UniqueFD epoll_fd_; - fxl::UniqueFD timer_fd_; + fml::UniqueFD epoll_fd_; + fml::UniqueFD timer_fd_; bool running_; MessageLoopLinux(); diff --git a/fml/platform/posix/file_posix.cc b/fml/platform/posix/file_posix.cc new file mode 100644 index 0000000000000..028f49f4d183d --- /dev/null +++ b/fml/platform/posix/file_posix.cc @@ -0,0 +1,71 @@ +// 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 { + +fml::UniqueFD OpenFile(const char* path, + OpenPermission permission, + bool is_directory) { + return OpenFile(fml::UniqueFD{AT_FDCWD}, path, permission, is_directory); +} + +fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory, + const char* path, + OpenPermission permission, + bool is_directory) { + if (path == nullptr) { + return fml::UniqueFD{}; + } + + int flags = 0; + switch (permission) { + case OpenPermission::kRead: + flags = O_RDONLY; + break; + case OpenPermission::kWrite: + flags = O_WRONLY; + break; + case OpenPermission::kReadWrite: + flags = O_RDWR; + break; + case OpenPermission::kExecute: + flags = O_RDONLY; + break; + } + + if (is_directory) { + flags |= O_DIRECTORY; + } + + return fml::UniqueFD{ + HANDLE_EINTR(::openat(base_directory.get(), path, flags))}; +} + +fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor) { + return fml::UniqueFD{HANDLE_EINTR(::dup(descriptor))}; +} + +bool IsDirectory(const fml::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/platform/posix/mapping_posix.cc b/fml/platform/posix/mapping_posix.cc index 07f7edb074ab9..fc53d6a4f7fc9 100644 --- a/fml/platform/posix/mapping_posix.cc +++ b/fml/platform/posix/mapping_posix.cc @@ -11,6 +11,7 @@ #include +#include "flutter/fml/unique_fd.h" #include "lib/fxl/build_config.h" #include "lib/fxl/files/eintr_wrapper.h" @@ -39,11 +40,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(fml::UniqueFD{HANDLE_EINTR(::open(path.c_str(), O_RDONLY))}, + executable) {} -FileMapping::FileMapping(const fxl::UniqueFD& handle) +FileMapping::FileMapping(const fml::UniqueFD& handle, bool executable) : size_(0), mapping_(nullptr) { if (!handle.is_valid()) { return; @@ -59,8 +60,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/platform/posix/native_library_posix.cc b/fml/platform/posix/native_library_posix.cc new file mode 100644 index 0000000000000..1255c38fc0821 --- /dev/null +++ b/fml/platform/posix/native_library_posix.cc @@ -0,0 +1,60 @@ +// 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/native_library.h" + +#include +#include + +namespace fml { + +NativeLibrary::NativeLibrary(const char* path) { + ::dlerror(); + handle_ = ::dlopen(path, RTLD_NOW); + if (handle_ == nullptr) { + FXL_LOG(ERROR) << "Could not open library '" << path << "' due to error '" + << ::dlerror() << "'."; + } +} + +NativeLibrary::NativeLibrary(Handle 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() + << "'."; + } + } +} + +NativeLibrary::Handle 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/platform/win/file_win.cc b/fml/platform/win/file_win.cc new file mode 100644 index 0000000000000..3f5e90494b013 --- /dev/null +++ b/fml/platform/win/file_win.cc @@ -0,0 +1,119 @@ +// 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 "flutter/fml/platform/win/wstring_conversion.h" + +namespace fml { + +fml::UniqueFD OpenFile(const std::wstring& path, + OpenPermission permission, + bool is_directory) { + if (path.size() == 0) { + return fml::UniqueFD{}; + } + + DWORD desired_access = 0; + + switch (permission) { + case OpenPermission::kRead: + desired_access = GENERIC_READ; + break; + case OpenPermission::kWrite: + desired_access = GENERIC_WRITE; + break; + case OpenPermission::kReadWrite: + desired_access = GENERIC_WRITE | GENERIC_READ; + break; + case OpenPermission::kExecute: + desired_access = GENERIC_READ | GENERIC_EXECUTE; + break; + } + + return fml::UniqueFD{::CreateFile( + path.c_str(), // lpFileName + desired_access, // dwDesiredAccess + FILE_SHARE_READ, // dwShareMode + 0, // lpSecurityAttributes + OPEN_EXISTING, // dwCreationDisposition + FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes + 0 // hTemplateFile + )}; +} + +fml::UniqueFD OpenFile(const char* path, + OpenPermission permission, + bool is_directory) { + return OpenFile(ConvertToWString(path), permission, is_directory); +} + +static std::wstring GetFullHandlePath(const fml::UniqueFD& handle) { + wchar_t buffer[MAX_PATH]; + + DWORD returned = ::GetFinalPathNameByHandle(handle.get(), buffer, MAX_PATH, + FILE_NAME_NORMALIZED); + if (returned == 0 || returned > MAX_PATH) { + return {}; + } + + return {buffer}; +} + +fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory, + const char* path, + OpenPermission permission, + bool is_directory) { + // If the base directory is invalid or the path is absolute, use the generic + // open file variant. + if (!base_directory.is_valid()) { + return OpenFile(path, permission, is_directory); + } + + const auto wpath = ConvertToWString(path); + + if (!::PathIsRelative(wpath.c_str())) { + return OpenFile(path, permission, is_directory); + } + + std::wstringstream stream; + stream << GetFullHandlePath(base_directory) << "\\" << path; + return OpenFile(stream.str(), permission, is_directory); +} + +fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor) { + if (descriptor == INVALID_HANDLE_VALUE) { + return fml::UniqueFD{}; + } + + HANDLE duplicated = INVALID_HANDLE_VALUE; + + if (!::DuplicateHandle( + GetCurrentProcess(), // source process + descriptor, // source handle + GetCurrentProcess(), // target process + &duplicated, // target handle + 0, // desired access (ignored because DUPLICATE_SAME_ACCESS) + FALSE, // inheritable + DUPLICATE_SAME_ACCESS) // options + ) { + return fml::UniqueFD{}; + } + + return fml::UniqueFD{duplicated}; +} + +bool IsDirectory(const fml::UniqueFD& directory) { + BY_HANDLE_FILE_INFORMATION info; + if (!::GetFileInformationByHandle(directory.get(), &info)) { + return false; + } + return info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; +} + +} // namespace fml diff --git a/fml/platform/win/mapping_win.cc b/fml/platform/win/mapping_win.cc index fd404a14f37dc..9dd5dcf6f2249 100644 --- a/fml/platform/win/mapping_win.cc +++ b/fml/platform/win/mapping_win.cc @@ -5,13 +5,13 @@ #include "flutter/fml/mapping.h" #include +#include +#include #include -#include "lib/fxl/build_config.h" - -#include -#include +#include "flutter/fml/file.h" +#include "flutter/fml/platform/win/wstring_conversion.h" using PlatformResourceMapping = fml::FileMapping; @@ -29,47 +29,50 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name) { return std::make_unique(resource_name); } -FileMapping::FileMapping(const std::string& path) - : size_(0), mapping_(nullptr) { - HANDLE file_handle_ = - CreateFileA(reinterpret_cast(path.c_str()), GENERIC_READ, - FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr); +FileMapping::FileMapping(const std::string& path, bool executable) + : FileMapping(OpenFile(path.c_str(), + executable ? OpenPermission::kExecute + : OpenPermission::kRead, + false), + executable) {} - if (file_handle_ == INVALID_HANDLE_VALUE) { +FileMapping::FileMapping(const fml::UniqueFD& fd, bool executable) + : size_(0), mapping_(nullptr) { + if (!fd.is_valid()) { return; } - size_ = GetFileSize(file_handle_, nullptr); - if (size_ == INVALID_FILE_SIZE) { - size_ = 0; - return; + if (auto size = ::GetFileSize(fd.get(), nullptr)) { + if (size > 0) { + size_ = size; + } else { + return; + } } - mapping_handle_ = CreateFileMapping(file_handle_, nullptr, PAGE_READONLY, 0, - size_, nullptr); + const DWORD protect = executable ? PAGE_EXECUTE_READ : PAGE_READONLY; - CloseHandle(file_handle_); + mapping_handle_.reset(::CreateFileMapping(fd.get(), // hFile + nullptr, // lpAttributes + protect, // flProtect + 0, // dwMaximumSizeHigh + 0, // dwMaximumSizeLow + nullptr // lpName + )); - if (mapping_handle_ == INVALID_HANDLE_VALUE) { + if (!mapping_handle_.is_valid()) { return; } - auto mapping = MapViewOfFile(mapping_handle_, FILE_MAP_READ, 0, 0, size_); - - if (mapping == INVALID_HANDLE_VALUE) { - CloseHandle(mapping_handle_); - mapping_handle_ = INVALID_HANDLE_VALUE; - return; - } + const DWORD desired_access = executable ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ; - mapping_ = static_cast(mapping); + mapping_ = reinterpret_cast( + MapViewOfFile(mapping_handle_.get(), desired_access, 0, 0, size_)); } FileMapping::~FileMapping() { if (mapping_ != nullptr) { UnmapViewOfFile(mapping_); - CloseHandle(mapping_handle_); } } diff --git a/fml/platform/win/native_library_win.cc b/fml/platform/win/native_library_win.cc new file mode 100644 index 0000000000000..6992f06f3e886 --- /dev/null +++ b/fml/platform/win/native_library_win.cc @@ -0,0 +1,51 @@ +// 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/native_library.h" + +#include + +#include "flutter/fml/platform/win/wstring_conversion.h" + +namespace fml { + +NativeLibrary::NativeLibrary(const char* path) + : handle_(nullptr), close_handle_(true) { + if (path == nullptr) { + return; + } + + handle_ = ::LoadLibrary(ConvertToWString(path).c_str()); +} + +NativeLibrary::NativeLibrary(Handle handle, bool close_handle) + : handle_(handle), close_handle_(close_handle) {} + +NativeLibrary::~NativeLibrary() { + if (handle_ != nullptr && close_handle_) { + ::FreeLibrary(handle_); + } +} + +NativeLibrary::Handle 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(::GetModuleHandle(nullptr), false)); +} + +const uint8_t* NativeLibrary::ResolveSymbol(const char* symbol) { + if (symbol == nullptr || handle_ == nullptr) { + return nullptr; + } + return reinterpret_cast(::GetProcAddress(handle_, symbol)); +} + +} // namespace fml diff --git a/fml/platform/win/wstring_conversion.h b/fml/platform/win/wstring_conversion.h new file mode 100644 index 0000000000000..0682dd84067bf --- /dev/null +++ b/fml/platform/win/wstring_conversion.h @@ -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. + +#ifndef FLUTTER_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_ +#define FLUTTER_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_ + +#include +#include +#include + +namespace fml { + +inline std::wstring ConvertToWString(const char* path) { + if (path == nullptr) { + return {}; + } + std::string path8(path); + std::wstring_convert, wchar_t> wchar_conv; + return wchar_conv.from_bytes(path8); +} + +} // namespace fml + +#endif // FLUTTER_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_ 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); diff --git a/fml/unique_fd.cc b/fml/unique_fd.cc new file mode 100644 index 0000000000000..bab79f7a9b743 --- /dev/null +++ b/fml/unique_fd.cc @@ -0,0 +1,35 @@ +// 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/unique_fd.h" + +#include "lib/fxl/files/eintr_wrapper.h" + +namespace fml { +namespace internal { + +#if OS_WIN + +namespace win { + +void UniqueFDTraits::Free(HANDLE fd) { + CloseHandle(fd); +} + +} // namespace win + +#else // OS_WIN + +namespace unix { + +void UniqueFDTraits::Free(int fd) { + IGNORE_EINTR(fd); +} + +} // namespace unix + +#endif // OS_WIN + +} // namespace internal +} // namespace fml diff --git a/fml/unique_fd.h b/fml/unique_fd.h new file mode 100644 index 0000000000000..9f2d796579d8c --- /dev/null +++ b/fml/unique_fd.h @@ -0,0 +1,60 @@ +// 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_UNIQUE_FD_H_ +#define FLUTTER_FML_UNIQUE_FD_H_ + +#include "flutter/fml/unique_object.h" +#include "lib/fxl/build_config.h" + +#if OS_WIN + +#include + +#endif // OS_WIN + +namespace fml { +namespace internal { + +#if OS_WIN + +namespace win { + +struct UniqueFDTraits { + static HANDLE InvalidValue() { return INVALID_HANDLE_VALUE; } + static bool IsValid(HANDLE value) { return value != InvalidValue(); } + static void Free(HANDLE fd); +}; + +} // namespace win + +#else // OS_WIN + +namespace unix { + +struct UniqueFDTraits { + static int InvalidValue() { return -1; } + static bool IsValid(int value) { return value >= 0; } + static void Free(int fd); +}; + +} // namespace unix + +#endif // OS_WIN + +} // namespace internal + +#if OS_WIN + +using UniqueFD = UniqueObject; + +#else // OS_WIN + +using UniqueFD = UniqueObject; + +#endif // OS_WIN + +} // namespace fml + +#endif // FLUTTER_FML_UNIQUE_FD_H_ diff --git a/fml/unique_object.h b/fml/unique_object.h new file mode 100644 index 0000000000000..e2487a53881a9 --- /dev/null +++ b/fml/unique_object.h @@ -0,0 +1,137 @@ +// 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_UNIQUE_OBJECT_H_ +#define FLUTTER_FML_UNIQUE_OBJECT_H_ + +#include + +#include "lib/fxl/compiler_specific.h" +#include "lib/fxl/logging.h" +#include "lib/fxl/macros.h" + +namespace fml { + +// struct UniqueFooTraits { +// // This function should be fast an inline. +// static int InvalidValue() { return 0; } +// +// // This function should be fast an inline. +// static bool IsValid(const T& value) { return value != InvalidValue(); } +// +// // This free function will not be called if f == InvalidValue()! +// static void Free(int f) { ::FreeFoo(f); } +// }; + +template +class UniqueObject { + private: + // This must be first since it's used inline below. + // + // Use the empty base class optimization to allow us to have a Traits + // member, while avoiding any space overhead for it when Traits is an + // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good + // discussion of this technique. + struct Data : public Traits { + explicit Data(const T& in) : generic(in) {} + Data(const T& in, const Traits& other) : Traits(other), generic(in) {} + + T generic; + }; + + public: + using element_type = T; + using traits_type = Traits; + + UniqueObject() : data_(Traits::InvalidValue()) {} + explicit UniqueObject(const T& value) : data_(value) {} + + UniqueObject(const T& value, const Traits& traits) : data_(value, traits) {} + + UniqueObject(UniqueObject&& other) + : data_(other.release(), other.get_traits()) {} + + ~UniqueObject() { FreeIfNecessary(); } + + UniqueObject& operator=(UniqueObject&& other) { + reset(other.release()); + return *this; + } + + void reset(const T& value = Traits::InvalidValue()) { + FXL_CHECK(data_.generic == Traits::InvalidValue() || + data_.generic != value); + FreeIfNecessary(); + data_.generic = value; + } + + void swap(UniqueObject& other) { + // Standard swap idiom: 'using std::swap' ensures that std::swap is + // present in the overload set, but we call swap unqualified so that + // any more-specific overloads can be used, if available. + using std::swap; + swap(static_cast(data_), static_cast(other.data_)); + swap(data_.generic, other.data_.generic); + } + + // Release the object. The return value is the current object held by this + // object. After this operation, this object will hold an invalid value, and + // will not own the object any more. + T release() FXL_WARN_UNUSED_RESULT { + T old_generic = data_.generic; + data_.generic = Traits::InvalidValue(); + return old_generic; + } + + const T& get() const { return data_.generic; } + + bool is_valid() const { return Traits::IsValid(data_.generic); } + + bool operator==(const T& value) const { return data_.generic == value; } + + bool operator!=(const T& value) const { return data_.generic != value; } + + Traits& get_traits() { return data_; } + const Traits& get_traits() const { return data_; } + + private: + void FreeIfNecessary() { + if (data_.generic != Traits::InvalidValue()) { + data_.Free(data_.generic); + data_.generic = Traits::InvalidValue(); + } + } + + // Forbid comparison. If U != T, it totally doesn't make sense, and if U == + // T, it still doesn't make sense because you should never have the same + // object owned by two different UniqueObject. + template + bool operator==(const UniqueObject& p2) const = delete; + + template + bool operator!=(const UniqueObject& p2) const = delete; + + Data data_; + + FXL_DISALLOW_COPY_AND_ASSIGN(UniqueObject); +}; + +template +void swap(const UniqueObject& a, const UniqueObject& b) { + a.swap(b); +} + +template +bool operator==(const T& value, const UniqueObject& object) { + return value == object.get(); +} + +template +bool operator!=(const T& value, const UniqueObject& object) { + return !(value == object.get()); +} + +} // namespace fml + +#endif // FLUTTER_FML_UNIQUE_OBJECT_H_ diff --git a/lib/snapshot/BUILD.gn b/lib/snapshot/BUILD.gn index 2b53ffc4d4f6d..8c568f4773c90 100644 --- a/lib/snapshot/BUILD.gn +++ b/lib/snapshot/BUILD.gn @@ -29,20 +29,40 @@ if (is_fuchsia) { # The sole purpose of this target is to generate a .packages file. sources = [] - infer_package_name = true + dot_packages_file = "$target_gen_dir/snapshot.packages" + outputs = [ + dot_packages_file, + ] + deps = [] + foreach(dep, dart_deps) { + deps += [ "$dep($dart_toolchain)" ] + } disable_analysis = true - deps = [ - "//topaz/public/dart/fuchsia", - "//topaz/public/dart/zircon", - ] + script = "//build/dart/gen_dot_packages.py" + args = [ + "--out", + rebase_path(dot_packages_file, root_build_dir), + "--source-dir", + rebase_path("."), + "--root-build-dir", + rebase_path(root_build_dir), + "--root-gen-dir", + rebase_path(dart_root_gen_dir), + "--package-name", + "snapshot_root", + "--depfile", + rebase_path(depfile), + "--deps", + ] + dart_deps } } action("generate_snapshot_bin") { if (is_fuchsia) { snapshot_dart = "snapshot_fuchsia.dart" + # TODO(rmacnak): Fuchsia cross builds use the wrong Dart target # architecture, and have added steps that depend on this error for # reasonable build times (e.g., invoking the analyzer). @@ -85,9 +105,9 @@ action("generate_snapshot_bin") { rebased_dart_ui_path = rebase_path(dart_ui_path) - gen_snapshot_dir = - get_label_info("//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)", - "root_out_dir") + gen_snapshot_dir = get_label_info( + "//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)", + "root_out_dir") script = "//third_party/dart/runtime/tools/create_snapshot_bin.py" args = [ @@ -209,7 +229,7 @@ bin_to_assembly("isolate_snapshot_data_assembly") { ] input = "$target_gen_dir/isolate_snapshot.bin" output = "$target_gen_dir/isolate_snapshot_data.S" - symbol = "kDartIsolateCoreSnapshotData" + symbol = "kDartIsolateSnapshotData" executable = false } @@ -219,7 +239,7 @@ bin_to_assembly("isolate_snapshot_instructions_assembly") { ] input = "$target_gen_dir/isolate_snapshot_instructions.bin" output = "$target_gen_dir/isolate_snapshot_instructions.S" - symbol = "kDartIsolateCoreSnapshotInstructions" + symbol = "kDartIsolateSnapshotInstructions" executable = true } @@ -249,9 +269,9 @@ compile_platform("non_strong_platform") { ] args = [ - "--target=flutter", - "dart:core", - ] + "--target=flutter", + "dart:core", + ] } compile_platform("strong_platform") { @@ -265,10 +285,10 @@ compile_platform("strong_platform") { ] args = [ - "--target=flutter", - "--strong", - "dart:core" - ] + "--target=flutter", + "--strong", + "dart:core", + ] } group("kernel_platform_files") { diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 8b3be72d5973b..6a75cd22c8614 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -40,14 +40,10 @@ source_set("ui") { "painting/picture.h", "painting/picture_recorder.cc", "painting/picture_recorder.h", - "painting/resource_context.cc", - "painting/resource_context.h", "painting/rrect.cc", "painting/rrect.h", "painting/shader.cc", "painting/shader.h", - "painting/utils.cc", - "painting/utils.h", "painting/vertices.cc", "painting/vertices.h", "semantics/semantics_node.cc", @@ -87,19 +83,18 @@ source_set("ui") { "window/window.h", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] deps = [ - "//third_party/dart/runtime/bin:embedded_dart_io", "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", + "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/runtime:test_font", "$flutter_root/sky/engine", "$flutter_root/third_party/txt", + "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/rapidjson", "//third_party/skia", "//third_party/skia:gpu", diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 006826abbfdf6..60b911cb4ddec 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -120,10 +120,11 @@ void SceneBuilder::addPicture(double dx, double dy, Picture* picture, int hints) { - layer_builder_->PushPicture(SkPoint::Make(dx, dy), // - picture->picture(), // - !!(hints & 1), // picture is complex - !!(hints & 2) // picture will change + layer_builder_->PushPicture( + SkPoint::Make(dx, dy), // + UIDartState::CreateGPUObject(picture->picture()), // + !!(hints & 1), // picture is complex + !!(hints & 2) // picture will change ); } diff --git a/lib/ui/compositing/scene_host.cc b/lib/ui/compositing/scene_host.cc index c0e4c5332580a..f5e0cfb3547d8 100644 --- a/lib/ui/compositing/scene_host.cc +++ b/lib/ui/compositing/scene_host.cc @@ -4,6 +4,7 @@ #include "flutter/lib/ui/compositing/scene_host.h" +#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/dart_args.h" #include "lib/tonic/dart_binding_macros.h" #include "lib/tonic/dart_library_natives.h" @@ -37,8 +38,9 @@ fxl::RefPtr SceneHost::create( } SceneHost::SceneHost(fxl::RefPtr export_token_handle) { - export_node_holder_ = - fxl::MakeRefCounted(export_token_handle); + export_node_holder_ = fxl::MakeRefCounted( + blink::UIDartState::Current()->GetTaskRunners().GetGPUTaskRunner(), + export_token_handle); } #else fxl::RefPtr SceneHost::create(Dart_Handle export_token_handle) { diff --git a/lib/ui/dart_runtime_hooks.cc b/lib/ui/dart_runtime_hooks.cc index edd51245b05db..32a244c9cb67d 100644 --- a/lib/ui/dart_runtime_hooks.cc +++ b/lib/ui/dart_runtime_hooks.cc @@ -8,7 +8,11 @@ #include #include +#include +#include + #include "flutter/common/settings.h" +#include "flutter/lib/ui/ui_dart_state.h" #include "lib/fxl/build_config.h" #include "lib/fxl/logging.h" #include "lib/tonic/converter/dart_converter.h" @@ -141,17 +145,43 @@ void DartRuntimeHooks::Install(IsolateType isolate_type, // Implementation of native functions which are used for some // test/debug functionality in standalone dart mode. void Logger_PrintString(Dart_NativeArguments args) { - intptr_t length = 0; - uint8_t* chars = nullptr; - Dart_Handle str = Dart_GetNativeArgument(args, 0); - Dart_Handle result = Dart_StringToUTF8(str, &chars, &length); - if (Dart_IsError(result)) { - Dart_PropagateError(result); - } else { + std::stringstream stream; + const auto& logger_prefix = UIDartState::Current()->logger_prefix(); + +#if !OS(ANDROID) + // Prepend all logs with the isolate debug name except on Android where that + // prefix is specified in the log tag. + if (logger_prefix.size() > 0) { + stream << logger_prefix << ": "; + } +#endif // !OS(ANDROID) + + // Append the log buffer obtained from Dart code. + { + Dart_Handle str = Dart_GetNativeArgument(args, 0); + uint8_t* chars = nullptr; + intptr_t length = 0; + Dart_Handle result = Dart_StringToUTF8(str, &chars, &length); + if (Dart_IsError(result)) { + Dart_PropagateError(result); + return; + } + if (length > 0) { + stream << std::string{reinterpret_cast(chars), + static_cast(length)}; + } + } + + const auto log_string = stream.str(); + const char* chars = log_string.c_str(); + const size_t length = log_string.size(); + + // Log using platform specific mechanisms + { #if defined(OS_ANDROID) // Write to the logcat on Android. - const char* tag = Settings::Get().log_tag.c_str(); - __android_log_print(ANDROID_LOG_INFO, tag, "%.*s", (int)length, chars); + __android_log_print(ANDROID_LOG_INFO, logger_prefix.c_str(), "%.*s", + (int)length, chars); #elif defined(OS_IOS) // Write to syslog on iOS. // @@ -159,26 +189,22 @@ void Logger_PrintString(Dart_NativeArguments args) { // iOS logging APIs altogether. syslog(1 /* LOG_ALERT */, "%.*s", (int)length, chars); #else - // On Fuchsia and in flutter_tester (on both macOS and Linux), write - // directly to stdout. - fwrite(chars, 1, length, stdout); - fputs("\n", stdout); - fflush(stdout); + std::cout << log_string << std::endl; #endif } + if (dart::bin::ShouldCaptureStdout()) { // For now we report print output on the Stdout stream. uint8_t newline[] = {'\n'}; - Dart_ServiceSendDataEvent("Stdout", "WriteEvent", chars, length); + Dart_ServiceSendDataEvent("Stdout", "WriteEvent", + reinterpret_cast(chars), length); Dart_ServiceSendDataEvent("Stdout", "WriteEvent", newline, sizeof(newline)); } } void ScheduleMicrotask(Dart_NativeArguments args) { Dart_Handle closure = Dart_GetNativeArgument(args, 0); - if (LogIfError(closure) || !Dart_IsClosure(closure)) - return; - tonic::DartMicrotaskQueue::GetForCurrentThread()->ScheduleMicrotask(closure); + UIDartState::Current()->ScheduleMicrotask(closure); } } // namespace blink diff --git a/lib/ui/painting/codec.cc b/lib/ui/painting/codec.cc index 3e47ba86d50a5..758a722b409e2 100644 --- a/lib/ui/painting/codec.cc +++ b/lib/ui/painting/codec.cc @@ -4,11 +4,11 @@ #include "flutter/lib/ui/painting/codec.h" -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/glue/trace_event.h" #include "flutter/lib/ui/painting/frame_info.h" -#include "flutter/lib/ui/painting/resource_context.h" #include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/logging.h" #include "lib/tonic/dart_binding_macros.h" #include "lib/tonic/dart_library_natives.h" #include "lib/tonic/dart_state.h" @@ -17,6 +17,10 @@ #include "third_party/skia/include/codec/SkCodec.h" #include "third_party/skia/include/core/SkPixelRef.h" +#ifdef ERROR +#undef ERROR +#endif + using tonic::DartInvoke; using tonic::DartPersistentValue; using tonic::ToDart; @@ -28,9 +32,9 @@ namespace { static constexpr const char* kInitCodecTraceTag = "InitCodec"; static constexpr const char* kCodecNextFrameTraceTag = "CodecNextFrame"; -void InvokeCodecCallback(fxl::RefPtr codec, - std::unique_ptr callback, - size_t trace_id) { +static void InvokeCodecCallback(fxl::RefPtr codec, + std::unique_ptr callback, + size_t trace_id) { tonic::DartState* dart_state = callback->dart_state().get(); if (!dart_state) { TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id); @@ -45,7 +49,9 @@ void InvokeCodecCallback(fxl::RefPtr codec, TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id); } -sk_sp DecodeImage(sk_sp buffer, size_t trace_id) { +static sk_sp DecodeImage(fml::WeakPtr context, + sk_sp buffer, + size_t trace_id) { TRACE_FLOW_STEP("flutter", kInitCodecTraceTag, trace_id); TRACE_EVENT0("flutter", "DecodeImage"); @@ -53,13 +59,11 @@ sk_sp DecodeImage(sk_sp buffer, size_t trace_id) { return nullptr; } - std::unique_ptr resourceContext = ResourceContext::Acquire(); - GrContext* context = resourceContext->Get(); if (context) { // This indicates that we do not want a "linear blending" decode. sk_sp dstColorSpace = nullptr; - return SkImage::MakeCrossContextFromEncoded(context, std::move(buffer), - false, dstColorSpace.get()); + return SkImage::MakeCrossContextFromEncoded( + context.get(), std::move(buffer), false, dstColorSpace.get()); } else { // Defer decoding until time of draw later on the GPU thread. Can happen // when GL operations are currently forbidden such as in the background @@ -68,7 +72,10 @@ sk_sp DecodeImage(sk_sp buffer, size_t trace_id) { } } -fxl::RefPtr InitCodec(sk_sp buffer, size_t trace_id) { +fxl::RefPtr InitCodec(fml::WeakPtr context, + sk_sp buffer, + fxl::RefPtr unref_queue, + size_t trace_id) { TRACE_FLOW_STEP("flutter", kInitCodecTraceTag, trace_id); TRACE_EVENT0("blink", "InitCodec"); @@ -86,27 +93,31 @@ fxl::RefPtr InitCodec(sk_sp buffer, size_t trace_id) { if (skCodec->getFrameCount() > 1) { return fxl::MakeRefCounted(std::move(skCodec)); } - auto skImage = DecodeImage(buffer, trace_id); + auto skImage = DecodeImage(context, buffer, trace_id); if (!skImage) { FXL_LOG(ERROR) << "DecodeImage failed"; return nullptr; } auto image = CanvasImage::Create(); - image->set_image(skImage); + image->set_image({skImage, unref_queue}); auto frameInfo = fxl::MakeRefCounted(std::move(image), 0); return fxl::MakeRefCounted(std::move(frameInfo)); } void InitCodecAndInvokeCodecCallback( + fxl::RefPtr ui_task_runner, + fml::WeakPtr context, + fxl::RefPtr unref_queue, std::unique_ptr callback, sk_sp buffer, size_t trace_id) { - auto codec = InitCodec(std::move(buffer), trace_id); - Threads::UI()->PostTask(fxl::MakeCopyable([ - callback = std::move(callback), codec = std::move(codec), trace_id - ]() mutable { - InvokeCodecCallback(std::move(codec), std::move(callback), trace_id); - })); + auto codec = + InitCodec(context, std::move(buffer), std::move(unref_queue), trace_id); + ui_task_runner->PostTask( + fxl::MakeCopyable([callback = std::move(callback), + codec = std::move(codec), trace_id]() mutable { + InvokeCodecCallback(std::move(codec), std::move(callback), trace_id); + })); } void InstantiateImageCodec(Dart_NativeArguments args) { @@ -133,14 +144,20 @@ void InstantiateImageCodec(Dart_NativeArguments args) { auto buffer = SkData::MakeWithCopy(list.data(), list.num_elements()); - Threads::IO()->PostTask(fxl::MakeCopyable([ - callback = std::make_unique( - tonic::DartState::Current(), callback_handle), - buffer = std::move(buffer), trace_id - ]() mutable { - InitCodecAndInvokeCodecCallback(std::move(callback), std::move(buffer), - trace_id); - })); + auto dart_state = UIDartState::Current(); + + const auto& task_runners = dart_state->GetTaskRunners(); + task_runners.GetIOTaskRunner()->PostTask(fxl::MakeCopyable( + [callback = std::make_unique( + tonic::DartState::Current(), callback_handle), + buffer = std::move(buffer), trace_id, + ui_task_runner = task_runners.GetUITaskRunner(), + context = dart_state->GetResourceContext(), + queue = UIDartState::Current()->GetSkiaUnrefQueue()]() mutable { + InitCodecAndInvokeCodecCallback(std::move(ui_task_runner), context, + std::move(queue), std::move(callback), + std::move(buffer), trace_id); + })); } bool copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) { @@ -213,7 +230,8 @@ MultiFrameCodec::MultiFrameCodec(std::unique_ptr codec) nextFrameIndex_ = 0; } -sk_sp MultiFrameCodec::GetNextFrameImage() { +sk_sp MultiFrameCodec::GetNextFrameImage( + fml::WeakPtr resourceContext) { SkBitmap& bitmap = frameBitmaps_[nextFrameIndex_]; if (!bitmap.getPixels()) { // We haven't decoded this frame yet const SkImageInfo info = codec_->getInfo().makeColorType(kN32_SkColorType); @@ -245,15 +263,13 @@ sk_sp MultiFrameCodec::GetNextFrameImage() { } } - std::unique_ptr resourceContext = ResourceContext::Acquire(); - GrContext* context = resourceContext->Get(); - if (context) { + if (resourceContext) { SkPixmap pixmap(bitmap.info(), bitmap.pixelRef()->pixels(), bitmap.pixelRef()->rowBytes()); // This indicates that we do not want a "linear blending" decode. sk_sp dstColorSpace = nullptr; - return SkImage::MakeCrossContextFromPixmap(context, pixmap, false, - dstColorSpace.get()); + return SkImage::MakeCrossContextFromPixmap(resourceContext.get(), pixmap, + false, dstColorSpace.get()); } else { // Defer decoding until time of draw later on the GPU thread. Can happen // when GL operations are currently forbidden such as in the background @@ -264,19 +280,22 @@ sk_sp MultiFrameCodec::GetNextFrameImage() { void MultiFrameCodec::GetNextFrameAndInvokeCallback( std::unique_ptr callback, + fxl::RefPtr ui_task_runner, + fml::WeakPtr resourceContext, + fxl::RefPtr unref_queue, size_t trace_id) { fxl::RefPtr frameInfo = NULL; - sk_sp skImage = GetNextFrameImage(); + sk_sp skImage = GetNextFrameImage(resourceContext); if (skImage) { fxl::RefPtr image = CanvasImage::Create(); - image->set_image(skImage); + image->set_image({skImage, std::move(unref_queue)}); frameInfo = fxl::MakeRefCounted( std::move(image), frameInfos_[nextFrameIndex_].fDuration); } nextFrameIndex_ = (nextFrameIndex_ + 1) % frameInfos_.size(); - Threads::UI()->PostTask(fxl::MakeCopyable( - [ callback = std::move(callback), frameInfo, trace_id ]() mutable { + ui_task_runner->PostTask(fxl::MakeCopyable( + [callback = std::move(callback), frameInfo, trace_id]() mutable { InvokeNextFrameCallback(frameInfo, std::move(callback), trace_id); })); @@ -293,13 +312,20 @@ Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle callback_handle) { return ToDart("Callback must be a function"); } - Threads::IO()->PostTask(fxl::MakeCopyable([ - callback = std::make_unique( - tonic::DartState::Current(), callback_handle), - this, trace_id - ]() mutable { - GetNextFrameAndInvokeCallback(std::move(callback), trace_id); - })); + auto dart_state = UIDartState::Current(); + + const auto& task_runners = dart_state->GetTaskRunners(); + + task_runners.GetIOTaskRunner()->PostTask(fxl::MakeCopyable( + [callback = std::make_unique( + tonic::DartState::Current(), callback_handle), + this, trace_id, ui_task_runner = task_runners.GetUITaskRunner(), + queue = UIDartState::Current()->GetSkiaUnrefQueue(), + context = dart_state->GetResourceContext()]() mutable { + GetNextFrameAndInvokeCallback(std::move(callback), + std::move(ui_task_runner), context, + std::move(queue), trace_id); + })); return Dart_Null(); } diff --git a/lib/ui/painting/codec.h b/lib/ui/painting/codec.h index 98e5bc56df375..9fdce1a8c1a33 100644 --- a/lib/ui/painting/codec.h +++ b/lib/ui/painting/codec.h @@ -43,11 +43,16 @@ class MultiFrameCodec : public Codec { private: MultiFrameCodec(std::unique_ptr codec); + ~MultiFrameCodec() {} - sk_sp GetNextFrameImage(); + sk_sp GetNextFrameImage(fml::WeakPtr resourceContext); + void GetNextFrameAndInvokeCallback( std::unique_ptr callback, + fxl::RefPtr ui_task_runner, + fml::WeakPtr resourceContext, + fxl::RefPtr unref_queue, size_t trace_id); const std::unique_ptr codec_; diff --git a/lib/ui/painting/gradient.cc b/lib/ui/painting/gradient.cc index f6bb864627740..52ccd63f3f5d3 100644 --- a/lib/ui/painting/gradient.cc +++ b/lib/ui/painting/gradient.cc @@ -48,10 +48,10 @@ void CanvasGradient::initLinear(const tonic::Float32List& end_points, static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor doesn't use int32_t."); - set_shader(SkGradientShader::MakeLinear( + set_shader(UIDartState::CreateGPUObject(SkGradientShader::MakeLinear( reinterpret_cast(end_points.data()), reinterpret_cast(colors.data()), color_stops.data(), - colors.num_elements(), tile_mode)); + colors.num_elements(), tile_mode))); } void CanvasGradient::initRadial(double center_x, @@ -73,14 +73,14 @@ void CanvasGradient::initRadial(double center_x, sk_matrix = ToSkMatrix(matrix4); } - set_shader(SkGradientShader::MakeRadial( + set_shader(UIDartState::CreateGPUObject(SkGradientShader::MakeRadial( SkPoint::Make(center_x, center_y), radius, reinterpret_cast(colors.data()), color_stops.data(), - colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr)); + colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr))); } -CanvasGradient::CanvasGradient() : Shader(nullptr) {} +CanvasGradient::CanvasGradient() = default; -CanvasGradient::~CanvasGradient() {} +CanvasGradient::~CanvasGradient() = default; } // namespace blink diff --git a/lib/ui/painting/image.cc b/lib/ui/painting/image.cc index 42e733241c990..a1b9b45cdc863 100644 --- a/lib/ui/painting/image.cc +++ b/lib/ui/painting/image.cc @@ -4,9 +4,7 @@ #include "flutter/lib/ui/painting/image.h" -#include "flutter/common/threads.h" #include "flutter/lib/ui/painting/image_encoding.h" -#include "flutter/lib/ui/painting/utils.h" #include "lib/tonic/converter/dart_converter.h" #include "lib/tonic/dart_args.h" #include "lib/tonic/dart_binding_macros.h" @@ -30,13 +28,9 @@ void CanvasImage::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } -CanvasImage::CanvasImage() {} +CanvasImage::CanvasImage() = default; -CanvasImage::~CanvasImage() { - // Skia objects must be deleted on the IO thread so that any associated GL - // objects will be cleaned up through the IO thread's GL context. - SkiaUnrefOnIOThread(&image_); -} +CanvasImage::~CanvasImage() = default; Dart_Handle CanvasImage::toByteData(int format, int quality, @@ -49,8 +43,8 @@ void CanvasImage::dispose() { } size_t CanvasImage::GetAllocationSize() { - if (image_) { - return image_->width() * image_->height() * 4; + if (auto image = image_.get()) { + return image->width() * image->height() * 4; } else { return sizeof(CanvasImage); } diff --git a/lib/ui/painting/image.h b/lib/ui/painting/image.h index a7ed4298506f5..aeec2a0149c73 100644 --- a/lib/ui/painting/image.h +++ b/lib/ui/painting/image.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_LIB_UI_PAINTING_IMAGE_H_ #define FLUTTER_LIB_UI_PAINTING_IMAGE_H_ +#include "flutter/flow/skia_gpu_object.h" +#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/dart_wrappable.h" #include "third_party/skia/include/core/SkImage.h" @@ -25,13 +27,18 @@ class CanvasImage final : public fxl::RefCountedThreadSafe, return fxl::MakeRefCounted(); } - int width() { return image_->width(); } - int height() { return image_->height(); } + int width() { return image_.get()->width(); } + + int height() { return image_.get()->height(); } + Dart_Handle toByteData(int format, int quality, Dart_Handle callback); + void dispose(); - const sk_sp& image() const { return image_; } - void set_image(sk_sp image) { image_ = std::move(image); } + sk_sp image() const { return image_.get(); } + void set_image(flow::SkiaGPUObject image) { + image_ = std::move(image); + } virtual size_t GetAllocationSize() override; @@ -40,7 +47,7 @@ class CanvasImage final : public fxl::RefCountedThreadSafe, private: CanvasImage(); - sk_sp image_; + flow::SkiaGPUObject image_; }; } // namespace blink diff --git a/lib/ui/painting/image_encoding.cc b/lib/ui/painting/image_encoding.cc index f356e955f6745..f010fce893d3e 100644 --- a/lib/ui/painting/image_encoding.cc +++ b/lib/ui/painting/image_encoding.cc @@ -4,13 +4,15 @@ #include "flutter/lib/ui/painting/image_encoding.h" -#include "flutter/common/threads.h" +#include +#include + +#include "flutter/common/task_runners.h" #include "flutter/lib/ui/painting/image.h" -#include "flutter/lib/ui/painting/resource_context.h" +#include "flutter/lib/ui/ui_dart_state.h" #include "lib/fxl/build_config.h" #include "lib/fxl/functional/make_copyable.h" #include "lib/tonic/dart_persistent_value.h" -#include "lib/tonic/dart_state.h" #include "lib/tonic/logging/dart_invoke.h" #include "lib/tonic/typed_data/uint8_list.h" #include "third_party/skia/include/core/SkEncodedImageFormat.h" @@ -52,10 +54,11 @@ void EncodeImageAndInvokeDataCallback( std::unique_ptr callback, sk_sp image, SkEncodedImageFormat format, - int quality) { + int quality, + fxl::RefPtr ui_task_runner) { sk_sp encoded = EncodeImage(std::move(image), format, quality); - Threads::UI()->PostTask( + ui_task_runner->PostTask( fxl::MakeCopyable([callback = std::move(callback), encoded]() mutable { InvokeDataCallback(std::move(callback), std::move(encoded)); })); @@ -101,10 +104,14 @@ Dart_Handle EncodeImage(CanvasImage* canvas_image, tonic::DartState::Current(), callback_handle); sk_sp image = canvas_image->image(); - Threads::IO()->PostTask(fxl::MakeCopyable( - [callback = std::move(callback), image, image_format, quality]() mutable { + const auto& task_runners = UIDartState::Current()->GetTaskRunners(); + + task_runners.GetIOTaskRunner()->PostTask(fxl::MakeCopyable( + [callback = std::move(callback), image, image_format, quality, + ui_task_runner = task_runners.GetUITaskRunner()]() mutable { EncodeImageAndInvokeDataCallback(std::move(callback), std::move(image), - image_format, quality); + image_format, quality, + std::move(ui_task_runner)); })); return Dart_Null(); diff --git a/lib/ui/painting/image_shader.cc b/lib/ui/painting/image_shader.cc index 0fabd134c737c..a4ddbba0ea24b 100644 --- a/lib/ui/painting/image_shader.cc +++ b/lib/ui/painting/image_shader.cc @@ -4,6 +4,7 @@ #include "flutter/lib/ui/painting/image_shader.h" +#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/converter/dart_converter.h" #include "lib/tonic/dart_args.h" #include "lib/tonic/dart_binding_macros.h" @@ -37,15 +38,17 @@ void ImageShader::initWithImage(CanvasImage* image, SkShader::TileMode tmx, SkShader::TileMode tmy, const tonic::Float64List& matrix4) { - if (!image) + if (!image) { Dart_ThrowException( ToDart("ImageShader constructor called with non-genuine Image.")); + } SkMatrix sk_matrix = ToSkMatrix(matrix4); - set_shader(image->image()->makeShader(tmx, tmy, &sk_matrix)); + set_shader(UIDartState::CreateGPUObject( + image->image()->makeShader(tmx, tmy, &sk_matrix))); } -ImageShader::ImageShader() : Shader(nullptr) {} +ImageShader::ImageShader() = default; -ImageShader::~ImageShader() {} +ImageShader::~ImageShader() = default; } // namespace blink diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 89ddbf5f41bb0..34f92b8c315fd 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -4,9 +4,8 @@ #include "flutter/lib/ui/painting/picture.h" -#include "flutter/common/threads.h" #include "flutter/lib/ui/painting/canvas.h" -#include "flutter/lib/ui/painting/utils.h" +#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/converter/dart_converter.h" #include "lib/tonic/dart_args.h" #include "lib/tonic/dart_binding_macros.h" @@ -23,24 +22,20 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); DART_BIND_ALL(Picture, FOR_EACH_BINDING) -fxl::RefPtr Picture::Create(sk_sp picture) { +fxl::RefPtr Picture::Create(flow::SkiaGPUObject picture) { return fxl::MakeRefCounted(std::move(picture)); } -Picture::Picture(sk_sp picture) : picture_(std::move(picture)) {} +Picture::Picture(flow::SkiaGPUObject picture) + : picture_(std::move(picture)) {} -Picture::~Picture() { - // Skia objects must be deleted on the IO thread so that any associated GL - // objects will be cleaned up through the IO thread's GL context. - SkiaUnrefOnIOThread(&picture_); -} +Picture::~Picture() = default; fxl::RefPtr Picture::toImage(int width, int height) { fxl::RefPtr image = CanvasImage::Create(); - // TODO(abarth): We should pass in an SkColorSpace at some point. - image->set_image(SkImage::MakeFromPicture( - picture_, SkISize::Make(width, height), nullptr, nullptr, - SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB())); + image->set_image(UIDartState::CreateGPUObject(SkImage::MakeFromPicture( + picture_.get(), SkISize::Make(width, height), nullptr, nullptr, + SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB()))); return image; } @@ -49,8 +44,8 @@ void Picture::dispose() { } size_t Picture::GetAllocationSize() { - if (picture_) { - return picture_->approximateBytesUsed(); + if (auto picture = picture_.get()) { + return picture->approximateBytesUsed(); } else { return sizeof(Picture); } diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 4a26d01c08374..d916086b02f02 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_LIB_UI_PAINTING_PICTURE_H_ #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_ +#include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/painting/image.h" #include "lib/tonic/dart_wrappable.h" #include "third_party/skia/include/core/SkPicture.h" @@ -23,9 +24,9 @@ class Picture : public fxl::RefCountedThreadSafe, public: ~Picture() override; - static fxl::RefPtr Create(sk_sp picture); + static fxl::RefPtr Create(flow::SkiaGPUObject picture); - const sk_sp& picture() const { return picture_; } + sk_sp picture() const { return picture_.get(); } fxl::RefPtr toImage(int width, int height); @@ -36,9 +37,9 @@ class Picture : public fxl::RefCountedThreadSafe, static void RegisterNatives(tonic::DartLibraryNatives* natives); private: - explicit Picture(sk_sp picture); + explicit Picture(flow::SkiaGPUObject picture); - sk_sp picture_; + flow::SkiaGPUObject picture_; }; } // namespace blink diff --git a/lib/ui/painting/picture_recorder.cc b/lib/ui/painting/picture_recorder.cc index adc73c0043920..e870e400a7230 100644 --- a/lib/ui/painting/picture_recorder.cc +++ b/lib/ui/painting/picture_recorder.cc @@ -50,8 +50,9 @@ SkCanvas* PictureRecorder::BeginRecording(SkRect bounds) { fxl::RefPtr PictureRecorder::endRecording() { if (!isRecording()) return nullptr; - fxl::RefPtr picture = - Picture::Create(picture_recorder_.finishRecordingAsPicture()); + + fxl::RefPtr picture = Picture::Create(UIDartState::CreateGPUObject( + picture_recorder_.finishRecordingAsPicture())); canvas_->Clear(); canvas_->ClearDartWrapper(); canvas_ = nullptr; diff --git a/lib/ui/painting/resource_context.cc b/lib/ui/painting/resource_context.cc deleted file mode 100644 index 1b9f71548c15f..0000000000000 --- a/lib/ui/painting/resource_context.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/lib/ui/painting/resource_context.h" - -#include - -#include "lib/fxl/logging.h" - -namespace blink { -namespace { - -static GrContext* g_context = nullptr; -static std::mutex g_mutex; -static volatile bool g_freeze = false; - -} // namespace - -ResourceContext::ResourceContext() { - g_mutex.lock(); -} - -ResourceContext::~ResourceContext() { - g_mutex.unlock(); -} - -void ResourceContext::Set(sk_sp context) { - FXL_DCHECK(!g_context); - g_context = context.release(); -} - -GrContext* ResourceContext::Get() { - return g_freeze ? nullptr : g_context; -} - -std::unique_ptr ResourceContext::Acquire() { - return std::make_unique(); -} - -void ResourceContext::Freeze() { - std::lock_guard lock(g_mutex); - g_freeze = true; -} - -void ResourceContext::Unfreeze() { - std::lock_guard lock(g_mutex); - g_freeze = false; -} - -} // namespace blink diff --git a/lib/ui/painting/resource_context.h b/lib/ui/painting/resource_context.h deleted file mode 100644 index 627b2053c2df9..0000000000000 --- a/lib/ui/painting/resource_context.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2016 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_LIB_UI_PAINTING_RESOURCE_CONTEXT_H_ -#define FLUTTER_LIB_UI_PAINTING_RESOURCE_CONTEXT_H_ - -#include "lib/fxl/macros.h" -#include "third_party/skia/include/gpu/GrContext.h" - -namespace blink { - -class ResourceContext { - public: - /** - * Globally set the GrContext singleton instance. - */ - static void Set(sk_sp context); - - /** - * Acquire a GrContext wrapping ResourceContext that's also an exclusive mutex - * on GrContext operations. - * - * Destructing the ResourceContext frees the mutex. - */ - static std::unique_ptr Acquire(); - - /** - * Synchronously signal a freeze on GrContext operations. - * - * ResourceContext instances will return nullptr on GrContext Get until - * unfrozen. - */ - static void Freeze(); - - /** - * Synchronously unfreeze GrContext operations. - * - * ResourceContext instances will continue to return the global GrContext - * instance on Get. - */ - static void Unfreeze(); - - ResourceContext(); - ~ResourceContext(); - - /** - * Returns global GrContext instance. May return null when operations are - * frozen. - * - * Happens on iOS when background operations on GrContext are forbidden. - */ - GrContext* Get(); - - FXL_DISALLOW_COPY_AND_ASSIGN(ResourceContext); -}; - -} // namespace blink - -#endif // FLUTTER_LIB_UI_PAINTING_RESOURCE_CONTEXT_H_ diff --git a/lib/ui/painting/shader.cc b/lib/ui/painting/shader.cc index d7d8ccf20aefc..7999b84dfcc29 100644 --- a/lib/ui/painting/shader.cc +++ b/lib/ui/painting/shader.cc @@ -4,19 +4,15 @@ #include "flutter/lib/ui/painting/shader.h" -#include "flutter/common/threads.h" -#include "flutter/lib/ui/painting/utils.h" +#include "flutter/lib/ui/ui_dart_state.h" namespace blink { IMPLEMENT_WRAPPERTYPEINFO(ui, Shader); -Shader::Shader(sk_sp shader) : shader_(shader) {} +Shader::Shader(flow::SkiaGPUObject shader) + : shader_(std::move(shader)) {} -Shader::~Shader() { - // Skia objects must be deleted on the IO thread so that any associated GL - // objects will be cleaned up through the IO thread's GL context. - SkiaUnrefOnIOThread(&shader_); -} +Shader::~Shader() = default; } // namespace blink diff --git a/lib/ui/painting/shader.h b/lib/ui/painting/shader.h index 9c0f3c601db56..205197250eb84 100644 --- a/lib/ui/painting/shader.h +++ b/lib/ui/painting/shader.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_LIB_UI_PAINTING_SHADER_H_ #define FLUTTER_LIB_UI_PAINTING_SHADER_H_ +#include "flutter/flow/skia_gpu_object.h" +#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/dart_wrappable.h" #include "third_party/skia/include/core/SkShader.h" @@ -18,14 +20,17 @@ class Shader : public fxl::RefCountedThreadSafe, public: ~Shader() override; - const sk_sp& shader() { return shader_; } - void set_shader(sk_sp shader) { shader_ = std::move(shader); } + sk_sp shader() { return shader_.get(); } + + void set_shader(flow::SkiaGPUObject shader) { + shader_ = std::move(shader); + } protected: - Shader(sk_sp shader); + Shader(flow::SkiaGPUObject shader = {}); private: - sk_sp shader_; + flow::SkiaGPUObject shader_; }; } // namespace blink diff --git a/lib/ui/painting/utils.cc b/lib/ui/painting/utils.cc deleted file mode 100644 index b3f87135ac0a8..0000000000000 --- a/lib/ui/painting/utils.cc +++ /dev/null @@ -1,46 +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. - -#include "flutter/lib/ui/painting/utils.h" -#include "flutter/common/threads.h" - -namespace blink { - -namespace { - -constexpr fxl::TimeDelta kDrainDelay = fxl::TimeDelta::FromMilliseconds(250); - -} // anonymous namespace - -SkiaUnrefQueue::SkiaUnrefQueue() : drain_pending_(false) {} - -SkiaUnrefQueue SkiaUnrefQueue::instance_; - -SkiaUnrefQueue& SkiaUnrefQueue::Get() { - return instance_; -} - -void SkiaUnrefQueue::Unref(SkRefCnt* object) { - std::lock_guard lock(mutex_); - objects_.push_back(object); - if (!drain_pending_) { - drain_pending_ = true; - Threads::IO()->PostDelayedTask([this] { Drain(); }, kDrainDelay); - } -} - -void SkiaUnrefQueue::Drain() { - std::deque skia_objects; - { - std::lock_guard lock(mutex_); - objects_.swap(skia_objects); - drain_pending_ = false; - } - - for (SkRefCnt* skia_object : skia_objects) { - skia_object->unref(); - } -} - -} // namespace blink diff --git a/lib/ui/painting/utils.h b/lib/ui/painting/utils.h deleted file mode 100644 index 02782c67962bc..0000000000000 --- a/lib/ui/painting/utils.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 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. - -#include "third_party/skia/include/core/SkRefCnt.h" - -#include -#include - -namespace blink { - -// A queue that holds Skia objects that must be destructed on the IO thread. -class SkiaUnrefQueue { - public: - static SkiaUnrefQueue& Get(); - - void Unref(SkRefCnt* object); - - private: - SkiaUnrefQueue(); - void Drain(); - - static SkiaUnrefQueue instance_; - - std::mutex mutex_; - std::deque objects_; - bool drain_pending_; -}; - -template -void SkiaUnrefOnIOThread(sk_sp* sp) { - T* object = sp->release(); - if (object) { - SkiaUnrefQueue::Get().Unref(object); - } -} - -} // namespace blink diff --git a/lib/ui/text/font_collection.cc b/lib/ui/text/font_collection.cc index d6407f9ed42e1..248468cc9701d 100644 --- a/lib/ui/text/font_collection.cc +++ b/lib/ui/text/font_collection.cc @@ -34,15 +34,9 @@ std::shared_ptr FontCollection::GetFontCollection() const { return collection_; } -void FontCollection::RegisterFontsFromAssetProvider( - fxl::RefPtr asset_provider) { - - if (!asset_provider){ - return; - } - +void FontCollection::RegisterFonts(const AssetManager& asset_manager) { std::vector manifest_data; - if (!asset_provider->GetAsBuffer("FontManifest.json", &manifest_data)) { + if (!asset_manager.GetAsBuffer("FontManifest.json", &manifest_data)) { FXL_DLOG(WARNING) << "Could not find the font manifest in the asset store."; return; } @@ -92,8 +86,8 @@ void FontCollection::RegisterFontsFromAssetProvider( // TODO: Handle weights and styles. std::vector font_data; - if (asset_provider->GetAsBuffer(font_asset->value.GetString(), - &font_data)) { + if (asset_manager.GetAsBuffer(font_asset->value.GetString(), + &font_data)) { // The data must be copied because it needs to be moved into the // typeface as a stream. auto data = diff --git a/lib/ui/text/font_collection.h b/lib/ui/text/font_collection.h index fb393b1582b79..ea9c2f46a96a0 100644 --- a/lib/ui/text/font_collection.h +++ b/lib/ui/text/font_collection.h @@ -7,10 +7,10 @@ #include #include -#include "flutter/assets/asset_provider.h" + +#include "flutter/assets/asset_manager.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_ptr.h" -#include "txt/asset_data_provider.h" #include "txt/font_collection.h" namespace blink { @@ -21,7 +21,8 @@ class FontCollection { std::shared_ptr GetFontCollection() const; - void RegisterFontsFromAssetProvider(fxl::RefPtr asset_provider); + void RegisterFonts(const AssetManager& asset_manager); + void RegisterTestFonts(); private: diff --git a/lib/ui/text/paragraph.cc b/lib/ui/text/paragraph.cc index 858ccd01d4ef6..fd00f6f51b3a3 100644 --- a/lib/ui/text/paragraph.cc +++ b/lib/ui/text/paragraph.cc @@ -5,7 +5,7 @@ #include "flutter/lib/ui/text/paragraph.h" #include "flutter/common/settings.h" -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/sky/engine/core/rendering/PaintInfo.h" #include "flutter/sky/engine/core/rendering/RenderParagraph.h" #include "flutter/sky/engine/core/rendering/RenderText.h" @@ -53,7 +53,8 @@ Paragraph::Paragraph(std::unique_ptr paragraph) Paragraph::~Paragraph() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); + destruction_task_runner_->PostTask( + [renderView]() { renderView->destroy(); }); } } diff --git a/lib/ui/text/paragraph.h b/lib/ui/text/paragraph.h index 1b2019373553a..b3a943209ab4c 100644 --- a/lib/ui/text/paragraph.h +++ b/lib/ui/text/paragraph.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_LIB_UI_TEXT_PARAGRAPH_H_ #define FLUTTER_LIB_UI_TEXT_PARAGRAPH_H_ +#include "flutter/fml/message_loop.h" #include "flutter/lib/ui/painting/canvas.h" #include "flutter/lib/ui/text/paragraph_impl.h" #include "flutter/lib/ui/text/paragraph_impl_blink.h" @@ -66,6 +67,10 @@ class Paragraph : public fxl::RefCountedThreadSafe, explicit Paragraph(std::unique_ptr paragraph); + // TODO: This can be removed when the render view association for the legacy + // runtime is removed. + fxl::RefPtr destruction_task_runner_ = + UIDartState::Current()->GetTaskRunners().GetUITaskRunner(); OwnPtr m_renderView; }; diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc index 44d05053ba342..b987e3fde6272 100644 --- a/lib/ui/text/paragraph_builder.cc +++ b/lib/ui/text/paragraph_builder.cc @@ -5,7 +5,7 @@ #include "flutter/lib/ui/text/paragraph_builder.h" #include "flutter/common/settings.h" -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/lib/ui/text/font_collection.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/sky/engine/core/rendering/RenderInline.h" @@ -205,9 +205,11 @@ fxl::RefPtr ParagraphBuilder::create( double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale) { - return fxl::MakeRefCounted(encoded, fontFamily, fontSize, - lineHeight, ellipsis, locale); + const std::string& locale, + bool use_blink) { + return fxl::MakeRefCounted( + encoded, fontFamily, fontSize, lineHeight, ellipsis, locale, + UIDartState::Current()->use_blink()); } ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, @@ -215,8 +217,10 @@ ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale) { - if (!Settings::Get().using_blink) { + const std::string& locale, + bool use_blink) + : m_useBlink(use_blink) { + if (!m_useBlink) { int32_t mask = encoded[0]; txt::ParagraphStyle style; if (mask & psTextAlignMask) @@ -275,7 +279,8 @@ ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, ParagraphBuilder::~ParagraphBuilder() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); + destruction_task_runner_->PostTask( + [renderView]() { renderView->destroy(); }); } } @@ -290,7 +295,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, int32_t mask = encoded[0]; - if (!Settings::Get().using_blink) { + if (!m_useBlink) { // Set to use the properties of the previous style if the property is not // explicitly given. txt::TextStyle style = m_paragraphBuilder->PeekStyle(); @@ -423,7 +428,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, } void ParagraphBuilder::pop() { - if (!Settings::Get().using_blink) { + if (!m_useBlink) { m_paragraphBuilder->Pop(); } else { // Blink Version. @@ -445,7 +450,7 @@ Dart_Handle ParagraphBuilder::addText(const std::u16string& text) { if (error_code != U_BUFFER_OVERFLOW_ERROR) return tonic::ToDart("string is not well-formed UTF-16"); - if (!Settings::Get().using_blink) { + if (!m_useBlink) { m_paragraphBuilder->AddText(text); } else { // Blink Version. @@ -464,7 +469,7 @@ Dart_Handle ParagraphBuilder::addText(const std::u16string& text) { fxl::RefPtr ParagraphBuilder::build() { m_currentRenderObject = nullptr; - if (!Settings::Get().using_blink) { + if (!m_useBlink) { return Paragraph::Create(m_paragraphBuilder->Build()); } else { return Paragraph::Create(m_renderView.release()); diff --git a/lib/ui/text/paragraph_builder.h b/lib/ui/text/paragraph_builder.h index 37a1e9a3e74cf..1c38d98696def 100644 --- a/lib/ui/text/paragraph_builder.h +++ b/lib/ui/text/paragraph_builder.h @@ -32,7 +32,8 @@ class ParagraphBuilder : public fxl::RefCountedThreadSafe, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale); + const std::string& locale, + bool use_blink); ~ParagraphBuilder() override; @@ -58,14 +59,20 @@ class ParagraphBuilder : public fxl::RefCountedThreadSafe, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale); + const std::string& locale, + bool use_blink); void createRenderView(); + // TODO: This can be removed when the render view association for the legacy + // runtime is removed. + fxl::RefPtr destruction_task_runner_ = + UIDartState::Current()->GetTaskRunners().GetUITaskRunner(); OwnPtr m_renderView; RenderObject* m_renderParagraph; RenderObject* m_currentRenderObject; std::unique_ptr m_paragraphBuilder; + bool m_useBlink; }; } // namespace blink diff --git a/lib/ui/text/paragraph_impl_blink.cc b/lib/ui/text/paragraph_impl_blink.cc index c7752c0a7c757..5c50f047afa33 100644 --- a/lib/ui/text/paragraph_impl_blink.cc +++ b/lib/ui/text/paragraph_impl_blink.cc @@ -4,7 +4,6 @@ #include "flutter/lib/ui/text/paragraph_impl_blink.h" -#include "flutter/common/threads.h" #include "flutter/lib/ui/text/paragraph.h" #include "flutter/lib/ui/text/paragraph_impl.h" #include "flutter/sky/engine/core/rendering/PaintInfo.h" @@ -30,7 +29,8 @@ ParagraphImplBlink::ParagraphImplBlink(PassOwnPtr renderView) ParagraphImplBlink::~ParagraphImplBlink() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); + destruction_task_runner_->PostTask( + [renderView]() { renderView->destroy(); }); } } diff --git a/lib/ui/text/paragraph_impl_blink.h b/lib/ui/text/paragraph_impl_blink.h index 79d89ad471962..ebd80f8dd5382 100644 --- a/lib/ui/text/paragraph_impl_blink.h +++ b/lib/ui/text/paragraph_impl_blink.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_BLINK_H_ #define FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_BLINK_H_ +#include "flutter/fml/message_loop.h" #include "flutter/lib/ui/painting/canvas.h" #include "flutter/lib/ui/text/paragraph_impl.h" #include "flutter/lib/ui/text/text_box.h" @@ -41,6 +42,10 @@ class ParagraphImplBlink : public ParagraphImpl { int absoluteOffsetForPosition(const PositionWithAffinity& position); + // TODO: This can be removed when the render view association for the legacy + // runtime is removed. + fxl::RefPtr destruction_task_runner_ = + UIDartState::Current()->GetTaskRunners().GetUITaskRunner(); OwnPtr m_renderView; }; diff --git a/lib/ui/text/paragraph_impl_txt.cc b/lib/ui/text/paragraph_impl_txt.cc index de8d8ff0b2fc3..28c6ea19a8157 100644 --- a/lib/ui/text/paragraph_impl_txt.cc +++ b/lib/ui/text/paragraph_impl_txt.cc @@ -4,7 +4,7 @@ #include "flutter/lib/ui/text/paragraph_impl_txt.h" -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/lib/ui/text/paragraph.h" #include "flutter/lib/ui/text/paragraph_impl.h" #include "lib/fxl/logging.h" diff --git a/lib/ui/ui_dart_state.cc b/lib/ui/ui_dart_state.cc index 3bdf21e6a1a93..8ef7ca98fd758 100644 --- a/lib/ui/ui_dart_state.cc +++ b/lib/ui/ui_dart_state.cc @@ -4,6 +4,7 @@ #include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/fml/message_loop.h" #include "flutter/lib/ui/window/window.h" #include "flutter/sky/engine/platform/fonts/FontSelector.h" #include "lib/tonic/converter/dart_converter.h" @@ -12,34 +13,44 @@ using tonic::ToDart; namespace blink { -IsolateClient::~IsolateClient() {} - -UIDartState::UIDartState(IsolateClient* isolate_client, - std::unique_ptr window, - int dirfd) - : tonic::DartState(dirfd), - isolate_client_(isolate_client), - main_port_(ILLEGAL_PORT), - window_(std::move(window)) {} +UIDartState::UIDartState(TaskRunners task_runners, + TaskObserverAdd add_callback, + TaskObserverRemove remove_callback, + fml::WeakPtr resource_context, + fxl::RefPtr skia_unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint, + std::string logger_prefix) + : task_runners_(std::move(task_runners)), + add_callback_(std::move(add_callback)), + remove_callback_(std::move(remove_callback)), + resource_context_(std::move(resource_context)), + advisory_script_uri_(std::move(advisory_script_uri)), + advisory_script_entrypoint_(std::move(advisory_script_entrypoint)), + logger_prefix_(std::move(logger_prefix)), + skia_unref_queue_(std::move(skia_unref_queue)), + weak_factory_(this) { + AddOrRemoveTaskObserver(true /* add */); +} UIDartState::~UIDartState() { - main_port_ = ILLEGAL_PORT; - // We've already destroyed the isolate. Revoke any weak ptrs held by - // DartPersistentValues so they don't try to enter the destroyed isolate to - // clean themselves up. - // TODO(abarth): Can we do this work in the base class? - weak_factory_.InvalidateWeakPtrs(); + AddOrRemoveTaskObserver(false /* remove */); } -UIDartState* UIDartState::CreateForChildIsolate() { - return new UIDartState(isolate_client_, nullptr); +const std::string& UIDartState::GetAdvisoryScriptURI() const { + return advisory_script_uri_; +} + +const std::string& UIDartState::GetAdvisoryScriptEntrypoint() const { + return advisory_script_entrypoint_; } void UIDartState::DidSetIsolate() { - FXL_DCHECK(!debug_name_prefix_.empty()); main_port_ = Dart_GetMainPortId(); std::ostringstream debug_name; - debug_name << debug_name_prefix_ << "$main-" << main_port_; + // main.dart$main-1234 + debug_name << advisory_script_uri_ << "$" << advisory_script_entrypoint_ + << "-" << main_port_; debug_name_ = debug_name.str(); } @@ -55,8 +66,48 @@ PassRefPtr UIDartState::font_selector() { return font_selector_; } -void UIDartState::set_debug_name_prefix(const std::string& debug_name_prefix) { - debug_name_prefix_ = debug_name_prefix; +void UIDartState::SetWindow(std::unique_ptr window) { + window_ = std::move(window); +} + +const TaskRunners& UIDartState::GetTaskRunners() const { + return task_runners_; +} + +fxl::RefPtr UIDartState::GetSkiaUnrefQueue() const { + return skia_unref_queue_; +} + +void UIDartState::ScheduleMicrotask(Dart_Handle closure) { + if (tonic::LogIfError(closure) || !Dart_IsClosure(closure)) { + return; + } + + microtask_queue_.ScheduleMicrotask(closure); +} + +void UIDartState::FlushMicrotasksNow() { + microtask_queue_.RunMicrotasks(); +} + +void UIDartState::AddOrRemoveTaskObserver(bool add) { + auto task_runner = task_runners_.GetUITaskRunner(); + if (!task_runner) { + // This may happen in case the isolate has no thread affinity (for example, + // the service isolate). + return; + } + FXL_DCHECK(add_callback_ && remove_callback_); + if (add) { + add_callback_(reinterpret_cast(this), + [this]() { this->FlushMicrotasksNow(); }); + } else { + remove_callback_(reinterpret_cast(this)); + } +} + +fml::WeakPtr UIDartState::GetResourceContext() const { + return resource_context_; } } // namespace blink diff --git a/lib/ui/ui_dart_state.h b/lib/ui/ui_dart_state.h index 0f7f9343d4958..a5c78c1671815 100644 --- a/lib/ui/ui_dart_state.h +++ b/lib/ui/ui_dart_state.h @@ -5,65 +5,106 @@ #ifndef FLUTTER_LIB_UI_UI_DART_STATE_H_ #define FLUTTER_LIB_UI_UI_DART_STATE_H_ +#include +#include #include +#include "flutter/common/settings.h" +#include "flutter/common/task_runners.h" +#include "flutter/flow/skia_gpu_object.h" +#include "flutter/fml/memory/weak_ptr.h" #include "flutter/sky/engine/wtf/RefPtr.h" #include "lib/fxl/build_config.h" +#include "lib/tonic/dart_microtask_queue.h" #include "lib/tonic/dart_persistent_value.h" #include "lib/tonic/dart_state.h" #include "third_party/dart/runtime/include/dart_api.h" +#include "third_party/skia/include/gpu/GrContext.h" namespace blink { class FontSelector; class Window; -class IsolateClient { - public: - virtual void DidCreateSecondaryIsolate(Dart_Isolate isolate) = 0; - virtual void DidShutdownMainIsolate() = 0; - - protected: - virtual ~IsolateClient(); -}; - class UIDartState : public tonic::DartState { public: - UIDartState(IsolateClient* isolate_client, - std::unique_ptr window, - int dirfd = -1); - ~UIDartState() override; - static UIDartState* Current(); - UIDartState* CreateForChildIsolate(); - - IsolateClient* isolate_client() const { return isolate_client_; } - void set_isolate_client(IsolateClient* isolate_client) { - isolate_client_ = isolate_client; - } Dart_Port main_port() const { return main_port_; } + const std::string& debug_name() const { return debug_name_; } + + const std::string& logger_prefix() const { return logger_prefix_; } + Window* window() const { return window_.get(); } - void set_debug_name_prefix(const std::string& debug_name_prefix); void set_font_selector(PassRefPtr selector); + PassRefPtr font_selector(); - bool is_controller_state() const { return is_controller_state_; } - void set_is_controller_state(bool value) { is_controller_state_ = value; } - bool shutting_down() const { return shutting_down_; } - void set_shutting_down(bool value) { shutting_down_ = value; } + + bool use_blink() const { return use_blink_; } + + const TaskRunners& GetTaskRunners() const; + + void ScheduleMicrotask(Dart_Handle handle); + + void FlushMicrotasksNow(); + + fxl::RefPtr GetSkiaUnrefQueue() const; + + fml::WeakPtr GetResourceContext() const; + + template + static flow::SkiaGPUObject CreateGPUObject(sk_sp object) { + if (!object) { + return {}; + } + auto state = UIDartState::Current(); + FXL_DCHECK(state); + auto queue = state->GetSkiaUnrefQueue(); + return {std::move(object), std::move(queue)}; + }; + + protected: + UIDartState(TaskRunners task_runners, + TaskObserverAdd add_callback, + TaskObserverRemove remove_callback, + fml::WeakPtr resource_context, + fxl::RefPtr skia_unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint, + std::string logger_prefix); + + ~UIDartState() override; + + void SetWindow(std::unique_ptr window); + + void set_use_blink(bool use_blink) { use_blink_ = use_blink; } + + const std::string& GetAdvisoryScriptURI() const; + + const std::string& GetAdvisoryScriptEntrypoint() const; private: void DidSetIsolate() override; - IsolateClient* isolate_client_; - Dart_Port main_port_; - std::string debug_name_prefix_; + const TaskRunners task_runners_; + const TaskObserverAdd add_callback_; + const TaskObserverRemove remove_callback_; + fml::WeakPtr resource_context_; + const std::string advisory_script_uri_; + const std::string advisory_script_entrypoint_; + const std::string logger_prefix_; + Dart_Port main_port_ = ILLEGAL_PORT; std::string debug_name_; std::unique_ptr window_; RefPtr font_selector_; - bool is_controller_state_; - bool shutting_down_ = false; + fxl::RefPtr skia_unref_queue_; + tonic::DartMicrotaskQueue microtask_queue_; + fml::WeakPtrFactory weak_factory_; + + void AddOrRemoveTaskObserver(bool add); + + bool use_blink_ = false; }; } // namespace blink diff --git a/lib/ui/window/platform_message_response_dart.cc b/lib/ui/window/platform_message_response_dart.cc index 065159b79713b..2cca2fd179888 100644 --- a/lib/ui/window/platform_message_response_dart.cc +++ b/lib/ui/window/platform_message_response_dart.cc @@ -6,7 +6,7 @@ #include -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/lib/ui/window/window.h" #include "lib/fxl/functional/make_copyable.h" #include "lib/tonic/dart_state.h" @@ -43,12 +43,14 @@ Dart_Handle WrapByteData(std::vector data) { } // anonymous namespace PlatformMessageResponseDart::PlatformMessageResponseDart( - tonic::DartPersistentValue callback) - : callback_(std::move(callback)) {} + tonic::DartPersistentValue callback, + fxl::RefPtr ui_task_runner) + : callback_(std::move(callback)), + ui_task_runner_(std::move(ui_task_runner)) {} PlatformMessageResponseDart::~PlatformMessageResponseDart() { if (!callback_.is_empty()) { - Threads::UI()->PostTask( + ui_task_runner_->PostTask( fxl::MakeCopyable([callback = std::move(callback_)]() mutable { callback.Clear(); })); @@ -60,7 +62,7 @@ void PlatformMessageResponseDart::Complete(std::vector data) { return; FXL_DCHECK(!is_complete_); is_complete_ = true; - Threads::UI()->PostTask(fxl::MakeCopyable( + ui_task_runner_->PostTask(fxl::MakeCopyable( [ callback = std::move(callback_), data = std::move(data) ]() mutable { tonic::DartState* dart_state = callback.dart_state().get(); if (!dart_state) @@ -77,7 +79,7 @@ void PlatformMessageResponseDart::CompleteEmpty() { return; FXL_DCHECK(!is_complete_); is_complete_ = true; - Threads::UI()->PostTask( + ui_task_runner_->PostTask( fxl::MakeCopyable([callback = std::move(callback_)]() mutable { tonic::DartState* dart_state = callback.dart_state().get(); if (!dart_state) diff --git a/lib/ui/window/platform_message_response_dart.h b/lib/ui/window/platform_message_response_dart.h index 51c55a930014b..67bfb3d359691 100644 --- a/lib/ui/window/platform_message_response_dart.h +++ b/lib/ui/window/platform_message_response_dart.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_LIB_UI_PLATFORM_PLATFORM_MESSAGE_RESPONSE_DART_H_ #define FLUTTER_LIB_UI_PLATFORM_PLATFORM_MESSAGE_RESPONSE_DART_H_ +#include "flutter/fml/message_loop.h" #include "flutter/lib/ui/window/platform_message_response.h" #include "lib/tonic/dart_persistent_value.h" @@ -19,10 +20,13 @@ class PlatformMessageResponseDart : public PlatformMessageResponse { void CompleteEmpty() override; protected: - explicit PlatformMessageResponseDart(tonic::DartPersistentValue callback); + explicit PlatformMessageResponseDart( + tonic::DartPersistentValue callback, + fxl::RefPtr ui_task_runner); ~PlatformMessageResponseDart() override; tonic::DartPersistentValue callback_; + fxl::RefPtr ui_task_runner_; }; } // namespace blink diff --git a/lib/ui/window/viewport_metrics.h b/lib/ui/window/viewport_metrics.h index 1e443ae8c1404..5085d06f42724 100644 --- a/lib/ui/window/viewport_metrics.h +++ b/lib/ui/window/viewport_metrics.h @@ -23,6 +23,25 @@ struct ViewportMetrics { int32_t physical_view_inset_left = 0; }; +struct LogicalSize { + double width = 0.0; + double height = 0.0; +}; + +struct LogicalInset { + double left = 0.0; + double top = 0.0; + double right = 0.0; + double bottom = 0.0; +}; + +struct LogicalMetrics { + LogicalSize size; + double scale = 1.0; + LogicalInset padding; + LogicalInset view_inset; +}; + } // namespace blink #endif // FLUTTER_LIB_UI_WINDOW_VIEWPORT_METRICS_H_ diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index e12e03f10d01f..4cce1cc5903b0 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -63,7 +63,8 @@ void SendPlatformMessage(Dart_Handle window, fxl::RefPtr response; if (!Dart_IsNull(callback)) { response = fxl::MakeRefCounted( - tonic::DartPersistentValue(dart_state, callback)); + tonic::DartPersistentValue(dart_state, callback), + dart_state->GetTaskRunners().GetUITaskRunner()); } if (Dart_IsNull(data.dart_handle())) { UIDartState::Current()->window()->client()->HandlePlatformMessage( @@ -254,7 +255,7 @@ void Window::BeginFrame(fxl::TimePoint frameTime) { Dart_NewInteger(microseconds), }); - tonic::DartMicrotaskQueue::GetForCurrentThread()->RunMicrotasks(); + UIDartState::Current()->FlushMicrotasksNow(); DartInvokeField(library_.value(), "_drawFrame", {}); } diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index ef0d7ef863a0e..2feeccb65f9cc 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -13,6 +13,7 @@ #include "flutter/lib/ui/window/viewport_metrics.h" #include "lib/fxl/time/time_point.h" #include "lib/tonic/dart_persistent_value.h" +#include "third_party/skia/include/gpu/GrContext.h" namespace tonic { class DartLibraryNatives; @@ -35,12 +36,14 @@ class WindowClient { virtual ~WindowClient(); }; -class Window { +class Window final { public: explicit Window(WindowClient* client); + ~Window(); WindowClient* client() const { return client_; } + const ViewportMetrics& viewport_metrics() { return viewport_metrics_; } void DidCreateIsolate(); diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index dea8a8906d031..455d7e228168f 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -4,6 +4,7 @@ import("//third_party/dart/runtime/bin/vmservice/vmservice_sources.gni") import("$flutter_root/common/config.gni") +import("$flutter_root/testing/testing.gni") action("gen_embedded_resources_cc") { script = "//third_party/dart/runtime/tools/create_resources.py" @@ -37,9 +38,7 @@ source_set("embedded_resources_cc") { deps = [ ":gen_embedded_resources_cc", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] } source_set("test_font") { @@ -50,9 +49,7 @@ source_set("test_font") { deps = [ "//third_party/skia", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] defines = [] if (flutter_runtime_mode == "debug" || current_toolchain == host_toolchain) { # Though the test font data is small, we dont want to add to the binary size @@ -63,16 +60,19 @@ source_set("test_font") { } source_set("runtime") { - sources = [ "asset_font_selector.cc", "asset_font_selector.h", - "dart_controller.cc", - "dart_controller.h", - "dart_init.cc", - "dart_init.h", + "dart_isolate.cc", + "dart_isolate.h", "dart_service_isolate.cc", "dart_service_isolate.h", + "dart_snapshot.cc", + "dart_snapshot.h", + "dart_snapshot_buffer.cc", + "dart_snapshot_buffer.h", + "dart_vm.cc", + "dart_vm.h", "embedder_resources.cc", "embedder_resources.h", "platform_impl.cc", @@ -81,8 +81,8 @@ source_set("runtime") { "runtime_controller.h", "runtime_delegate.cc", "runtime_delegate.h", - "runtime_init.cc", - "runtime_init.h", + "service_protocol.cc", + "service_protocol.h", "start_up.cc", "start_up.h", "test_font_selector.cc", @@ -92,25 +92,24 @@ source_set("runtime") { deps = [ ":embedded_resources_cc", ":test_font", - "//third_party/dart/runtime:dart_api", - "//third_party/dart/runtime/bin:embedded_dart_io", "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", + "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/lib/io", "$flutter_root/lib/ui", "$flutter_root/sky/engine/platform", "$flutter_root/third_party/txt", "//garnet/public/lib/fxl", + "//third_party/dart/runtime:dart_api", + "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/rapidjson", "//third_party/skia", "//topaz/lib/tonic", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] # In AOT mode, precompiled snapshots contain the instruction buffer. # Generation of the same requires all application specific script code to be @@ -119,3 +118,28 @@ source_set("runtime") { deps += [ "$flutter_root/lib/snapshot" ] } } + +test_fixtures("runtime_fixtures") { + fixtures = [ "fixtures/simple_main.dart" ] +} + +executable("runtime_unittests") { + testonly = true + + sources = [ + "dart_isolate_unittests.cc", + "dart_vm_unittests.cc", + ] + + deps = [ + ":runtime", + ":runtime_fixtures", + "$flutter_root/fml", + "$flutter_root/lib/snapshot", + "$flutter_root/testing", + "//garnet/public/lib/fxl", + "//third_party/dart/runtime:libdart_jit", + "//third_party/skia", + "//topaz/lib/tonic", + ] +} diff --git a/runtime/asset_font_selector.cc b/runtime/asset_font_selector.cc index abf4bf9874ddd..2a43f39e3a89b 100644 --- a/runtime/asset_font_selector.cc +++ b/runtime/asset_font_selector.cc @@ -80,27 +80,15 @@ struct FontMatcher { } // namespace -void AssetFontSelector::Install( - fxl::RefPtr asset_provider) { +void AssetFontSelector::Install(fxl::RefPtr asset_manager) { RefPtr font_selector = - adoptRef(new AssetFontSelector(std::move(asset_provider))); + adoptRef(new AssetFontSelector(std::move(asset_manager))); font_selector->parseFontManifest(); UIDartState::Current()->set_font_selector(font_selector); } -void AssetFontSelector::Install(fxl::RefPtr asset_store) { - RefPtr font_selector = - adoptRef(new AssetFontSelector(std::move(asset_store))); - font_selector->parseFontManifest(); - UIDartState::Current()->set_font_selector(font_selector); -} - -AssetFontSelector::AssetFontSelector( - fxl::RefPtr asset_provider) - : asset_provider_(std::move(asset_provider)) {} - -AssetFontSelector::AssetFontSelector(fxl::RefPtr asset_store) - : asset_store_(std::move(asset_store)) {} +AssetFontSelector::AssetFontSelector(fxl::RefPtr asset_manager) + : asset_manager_(std::move(asset_manager)) {} AssetFontSelector::~AssetFontSelector() {} @@ -118,12 +106,9 @@ AssetFontSelector::FlutterFontAttributes::~FlutterFontAttributes() {} void AssetFontSelector::parseFontManifest() { std::vector font_manifest_data; - if (!asset_provider_ || - !asset_provider_->GetAsBuffer(kFontManifestAssetPath, - &font_manifest_data)) { - if (!asset_store_ || - !asset_store_->GetAsBuffer(kFontManifestAssetPath, &font_manifest_data)) - return; + if (!asset_manager_->GetAsBuffer(kFontManifestAssetPath, + &font_manifest_data)) { + return; } rapidjson::Document document; @@ -239,13 +224,8 @@ sk_sp AssetFontSelector::getTypefaceAsset( } std::unique_ptr typeface_asset(new TypefaceAsset); - if (!asset_provider_ || !asset_provider_->GetAsBuffer( - asset_path, &typeface_asset->data)) { - if (!asset_store_ || - !asset_store_->GetAsBuffer(asset_path, &typeface_asset->data)) { - typeface_cache_.insert(std::make_pair(asset_path, nullptr)); - return nullptr; - } + if (!asset_manager_->GetAsBuffer(asset_path, &typeface_asset->data)) { + return nullptr; } sk_sp font_mgr(SkFontMgr::RefDefault()); diff --git a/runtime/asset_font_selector.h b/runtime/asset_font_selector.h index 921c0472dba78..8d7e946d89e7e 100644 --- a/runtime/asset_font_selector.h +++ b/runtime/asset_font_selector.h @@ -8,7 +8,7 @@ #include #include -#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/assets/asset_manager.h" #include "flutter/assets/zip_asset_store.h" #include "flutter/sky/engine/platform/fonts/FontCacheKey.h" #include "flutter/sky/engine/platform/fonts/FontSelector.h" @@ -24,11 +24,7 @@ class AssetFontSelector : public FontSelector { ~AssetFontSelector() override; - static void Install(fxl::RefPtr asset_provider); - - // TODO(zarah): Remove this and related code using asset_store once flx is - // removed. - static void Install(fxl::RefPtr asset_store); + static void Install(fxl::RefPtr asset_manager); PassRefPtr getFontData(const FontDescription& font_description, const AtomicString& family_name) override; @@ -44,19 +40,14 @@ class AssetFontSelector : public FontSelector { private: struct TypefaceAsset; - explicit AssetFontSelector( - fxl::RefPtr asset_provider); - - explicit AssetFontSelector(fxl::RefPtr asset_store); + explicit AssetFontSelector(fxl::RefPtr asset_manager); void parseFontManifest(); sk_sp getTypefaceAsset(const FontDescription& font_description, const AtomicString& family_name); - fxl::RefPtr asset_provider_; - - fxl::RefPtr asset_store_; + fxl::RefPtr asset_manager_; HashMap> font_family_map_; diff --git a/runtime/dart_controller.cc b/runtime/dart_controller.cc deleted file mode 100644 index 84cfceeaecc10..0000000000000 --- a/runtime/dart_controller.cc +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2015 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. - -#include "flutter/runtime/dart_controller.h" -#include "lib/fxl/build_config.h" - -#if defined(OS_WIN) -#include -#undef GetCurrentDirectory -#endif - -#include - -#include "flutter/common/settings.h" -#include "flutter/common/threads.h" -#include "flutter/glue/trace_event.h" -#include "flutter/lib/io/dart_io.h" -#include "flutter/lib/ui/dart_runtime_hooks.h" -#include "flutter/lib/ui/dart_ui.h" -#include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/runtime/dart_init.h" -#include "flutter/runtime/dart_service_isolate.h" -#include "lib/fxl/files/directory.h" -#include "lib/fxl/files/path.h" -#include "lib/tonic/dart_class_library.h" -#include "lib/tonic/dart_message_handler.h" -#include "lib/tonic/dart_state.h" -#include "lib/tonic/dart_wrappable.h" -#include "lib/tonic/file_loader/file_loader.h" -#include "lib/tonic/logging/dart_error.h" -#include "lib/tonic/logging/dart_invoke.h" -#include "lib/tonic/scopes/dart_api_scope.h" -#include "lib/tonic/scopes/dart_isolate_scope.h" -#include "third_party/dart/runtime/include/dart_tools_api.h" - -using tonic::LogIfError; -using tonic::ToDart; - -namespace blink { -namespace { -#if defined(OS_WIN) - -std::string FindAndReplace(const std::string& str, - const std::string& findStr, - const std::string& replaceStr) { - std::string rStr = str; - size_t pos = 0; - while ((pos = rStr.find(findStr, pos)) != std::string::npos) { - rStr.replace(pos, findStr.length(), replaceStr); - pos += replaceStr.length(); - } - return rStr; -} - -std::string SanitizePath(const std::string& path) { - return FindAndReplace(path, "\\\\", "/"); -} - -std::string ResolvePath(std::string path) { - std::string sanitized = SanitizePath(path); - if ((sanitized.length() > 2) && (sanitized[1] == ':')) { - return sanitized; - } - return files::SimplifyPath(files::GetCurrentDirectory() + "/" + sanitized); -} - -#else // defined(OS_WIN) - -std::string SanitizePath(const std::string& path) { - return path; -} - -// TODO(abarth): Consider adding this to //garnet/public/lib/fxl. -std::string ResolvePath(std::string path) { - if (!path.empty() && path[0] == '/') - return path; - return files::SimplifyPath(files::GetCurrentDirectory() + "/" + path); -} - -#endif - -} // namespace - -DartController::DartController() : ui_dart_state_(nullptr) {} - -DartController::~DartController() { - if (ui_dart_state_) { - ui_dart_state_->set_isolate_client(nullptr); - - if (!ui_dart_state_->shutting_down()) { - // 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(); - } - } -} - -const std::string DartController::main_entrypoint_ = "main"; - -bool DartController::SendStartMessage(Dart_Handle root_library, - const std::string& entrypoint) { - if (LogIfError(root_library)) - return true; - - { - // Temporarily exit the isolate while we make it runnable. - Dart_Isolate isolate = dart_state()->isolate(); - FXL_DCHECK(Dart_CurrentIsolate() == isolate); - Dart_ExitIsolate(); - Dart_IsolateMakeRunnable(isolate); - Dart_EnterIsolate(isolate); - } - - // In order to support pausing the isolate at start, we indirectly invoke - // main by sending a message to the isolate. - - // Get the closure of main(). - Dart_Handle main_closure = Dart_GetClosure( - root_library, Dart_NewStringFromCString(entrypoint.c_str())); - if (LogIfError(main_closure)) - return true; - - // Grab the 'dart:isolate' library. - Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate")); - DART_CHECK_VALID(isolate_lib); - - // Send the start message containing the entry point by calling - // _startMainIsolate in dart:isolate. - const intptr_t kNumIsolateArgs = 2; - Dart_Handle isolate_args[kNumIsolateArgs]; - isolate_args[0] = main_closure; - isolate_args[1] = Dart_Null(); - Dart_Handle result = Dart_Invoke(isolate_lib, ToDart("_startMainIsolate"), - kNumIsolateArgs, isolate_args); - return LogIfError(result); -} - -tonic::DartErrorHandleType DartController::RunFromKernel( - const std::vector& kernel, - const std::string& entrypoint) { - tonic::DartState::Scope scope(dart_state()); - tonic::DartErrorHandleType error = tonic::kNoError; - if (Dart_IsNull(Dart_RootLibrary())) { - Dart_Handle result = Dart_LoadScriptFromKernel(kernel.data(), kernel.size()); - LogIfError(result); - error = tonic::GetErrorHandleType(result); - } - if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { - return tonic::kUnknownErrorType; - } - return error; -} - -tonic::DartErrorHandleType DartController::RunFromPrecompiledSnapshot( - const std::string& entrypoint) { - TRACE_EVENT0("flutter", "DartController::RunFromPrecompiledSnapshot"); - FXL_DCHECK(Dart_CurrentIsolate() == nullptr); - tonic::DartState::Scope scope(dart_state()); - if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { - return tonic::kUnknownErrorType; - } - return tonic::kNoError; -} - -tonic::DartErrorHandleType DartController::RunFromScriptSnapshot( - const uint8_t* buffer, - size_t size, - const std::string& entrypoint) { - tonic::DartState::Scope scope(dart_state()); - tonic::DartErrorHandleType error = tonic::kNoError; - if (Dart_IsNull(Dart_RootLibrary())) { - Dart_Handle result = Dart_LoadScriptFromSnapshot(buffer, size); - LogIfError(result); - error = tonic::GetErrorHandleType(result); - } - if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { - return tonic::kUnknownErrorType; - } - return error; -} - -tonic::DartErrorHandleType DartController::RunFromSource( - const std::string& main, - const std::string& packages) { - tonic::DartState::Scope scope(dart_state()); - tonic::DartErrorHandleType error = tonic::kNoError; - if (Dart_IsNull(Dart_RootLibrary())) { - tonic::FileLoader& loader = dart_state()->file_loader(); - if (!packages.empty() && !loader.LoadPackagesMap(ResolvePath(packages))) - FXL_LOG(WARNING) << "Failed to load package map: " << packages; - Dart_Handle result = loader.LoadScript(SanitizePath(main)); - LogIfError(result); - error = tonic::GetErrorHandleType(result); - } - if (SendStartMessage(Dart_RootLibrary())) { - return tonic::kCompilationErrorType; - } - return error; -} - -void DartController::CreateIsolateFor(const std::string& script_uri, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instr, - std::unique_ptr state) { - char* error = nullptr; - - void* platform_kernel = GetKernelPlatformBinary(); - - Dart_Isolate isolate; - if (platform_kernel != nullptr) { - isolate = Dart_CreateIsolateFromKernel( - script_uri.c_str(), "main", platform_kernel, nullptr /* flags */, - static_cast(state.get()), &error); - } else { - isolate = - Dart_CreateIsolate(script_uri.c_str(), "main", isolate_snapshot_data, - isolate_snapshot_instr, nullptr, - static_cast(state.get()), &error); - } - FXL_CHECK(isolate) << error; - ui_dart_state_ = state.release(); - ui_dart_state_->set_is_controller_state(true); - dart_state()->message_handler().Initialize(blink::Threads::UI()); - - Dart_SetShouldPauseOnStart(Settings::Get().start_paused); - - ui_dart_state_->set_debug_name_prefix(script_uri); - ui_dart_state_->SetIsolate(isolate); - FXL_CHECK(!LogIfError( - Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); - - { - tonic::DartApiScope dart_api_scope; - DartIO::InitForIsolate(); - DartUI::InitForIsolate(); - DartRuntimeHooks::Install(DartRuntimeHooks::MainIsolate, script_uri); - - std::unique_ptr ui_class_provider( - new tonic::DartClassProvider(dart_state(), "dart:ui")); - dart_state()->class_library().add_provider("ui", - std::move(ui_class_provider)); - } - Dart_ExitIsolate(); -} - -} // namespace blink diff --git a/runtime/dart_controller.h b/runtime/dart_controller.h deleted file mode 100644 index 4b11a8660b7e7..0000000000000 --- a/runtime/dart_controller.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015 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_RUNTIME_DART_CONTROLLER_H_ -#define FLUTTER_RUNTIME_DART_CONTROLLER_H_ - -#include -#include - -#include "lib/fxl/macros.h" -#include "lib/tonic/logging/dart_error.h" -#include "third_party/dart/runtime/include/dart_api.h" - -namespace blink { -class UIDartState; - -class DartController { - public: - DartController(); - ~DartController(); - - tonic::DartErrorHandleType RunFromKernel( - const std::vector& kernel, - const std::string& entrypoint = main_entrypoint_); - tonic::DartErrorHandleType RunFromPrecompiledSnapshot( - const std::string& entrypoint = main_entrypoint_); - tonic::DartErrorHandleType RunFromScriptSnapshot( - const uint8_t* buffer, - size_t size, - const std::string& entrypoint = main_entrypoint_); - tonic::DartErrorHandleType RunFromSource(const std::string& main, - const std::string& packages); - - void CreateIsolateFor(const std::string& script_uri, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instr, - std::unique_ptr ui_dart_state); - - UIDartState* dart_state() const { return ui_dart_state_; } - - private: - bool SendStartMessage(Dart_Handle root_library, - const std::string& entrypoint = main_entrypoint_); - - static const std::string main_entrypoint_; - - // The DartState associated with the main isolate. - UIDartState* ui_dart_state_; - - FXL_DISALLOW_COPY_AND_ASSIGN(DartController); -}; -} // namespace blink - -#endif // FLUTTER_RUNTIME_DART_CONTROLLER_H_ diff --git a/runtime/dart_init.cc b/runtime/dart_init.cc deleted file mode 100644 index e3d88322a4882..0000000000000 --- a/runtime/dart_init.cc +++ /dev/null @@ -1,725 +0,0 @@ -// Copyright 2015 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. - -#include "flutter/runtime/dart_init.h" -#include "flutter/sky/engine/wtf/OperatingSystem.h" - -#include -#include -#include - -#if defined(OS_WIN) -#include -#include -#undef ERROR - -#define access _access -#define R_OK 0x4 - -#ifndef S_ISDIR -#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) -#endif - -#else -#include -#endif - -#include -#include -#include -#include - -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/assets/unzipper_provider.h" -#include "flutter/assets/zip_asset_store.h" -#include "flutter/common/settings.h" -#include "flutter/glue/trace_event.h" -#include "flutter/lib/io/dart_io.h" -#include "flutter/lib/ui/dart_runtime_hooks.h" -#include "flutter/lib/ui/dart_ui.h" -#include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/lib/ui/window/window.h" -#include "flutter/runtime/dart_service_isolate.h" -#include "flutter/runtime/start_up.h" -#include "lib/fxl/arraysize.h" -#include "lib/fxl/build_config.h" -#include "lib/fxl/files/path.h" -#include "lib/fxl/files/file.h" -#include "lib/fxl/logging.h" -#include "lib/fxl/time/time_delta.h" -#include "lib/tonic/converter/dart_converter.h" -#include "lib/tonic/dart_class_library.h" -#include "lib/tonic/dart_state.h" -#include "lib/tonic/dart_sticky_error.h" -#include "lib/tonic/dart_wrappable.h" -#include "lib/tonic/file_loader/file_loader.h" -#include "lib/tonic/logging/dart_error.h" -#include "lib/tonic/logging/dart_invoke.h" -#include "lib/tonic/scopes/dart_api_scope.h" -#include "lib/tonic/scopes/dart_isolate_scope.h" -#include "lib/tonic/typed_data/uint8_list.h" -#include "third_party/dart/runtime/bin/embedded_dart_io.h" -#include "third_party/dart/runtime/include/dart_mirrors_api.h" - -using tonic::DartClassProvider; -using tonic::LogIfError; -using tonic::ToDart; - -namespace dart { -namespace observatory { - -#if !OS(FUCHSIA) && FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE - -// These two symbols are defined in |observatory_archive.cc| which is generated -// by the |//third_party/dart/runtime/observatory:archive_observatory| rule. -// Both of these symbols will be part of the data segment and therefore are read -// only. -extern unsigned int observatory_assets_archive_len; -extern const uint8_t* observatory_assets_archive; - -#endif // FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE - -} // namespace observatory -} // namespace dart - -namespace blink { - -const char kKernelAssetKey[] = "kernel_blob.bin"; -const char kSnapshotAssetKey[] = "snapshot_blob.bin"; -const char kPlatformKernelAssetKey[] = "platform.dill"; - -namespace { - -// Arguments passed to the Dart VM in all configurations. -static const char* kDartLanguageArgs[] = { - "--enable_mirrors=false", "--background_compilation", "--await_is_keyword", - "--causal_async_stacks", "--limit-ints-to-64-bits", -}; - -static const char* kDartPrecompilationArgs[] = { - "--precompilation", -}; - -static const char* kDartWriteProtectCodeArgs[] FXL_ALLOW_UNUSED_TYPE = { - "--no_write_protect_code", -}; - -static const char* kDartAssertArgs[] = { - // clang-format off - "--enable_asserts", - // clang-format on -}; - -static const char* kDartCheckedModeArgs[] = { - // clang-format off - "--enable_type_checks", - "--error_on_bad_type", - "--error_on_bad_override", - // clang-format on -}; - -static const char* kDartStrongModeArgs[] = { - // clang-format off - "--limit_ints_to_64_bits", - "--reify_generic_functions", - "--strong", - "--sync_async", - // clang-format on -}; - -static const char* kDartStartPausedArgs[]{ - "--pause_isolates_on_start", -}; - -static const char* kDartTraceStartupArgs[]{ - "--timeline_streams=Compiler,Dart,Embedder,GC", -}; - -static const char* kDartEndlessTraceBufferArgs[]{ - "--timeline_recorder=endless", -}; - -static const char* kDartFuchsiaTraceArgs[] FXL_ALLOW_UNUSED_TYPE = { - "--systrace_timeline", - "--timeline_streams=VM,Isolate,Compiler,Dart,GC", -}; - -constexpr char kFileUriPrefix[] = "file://"; -constexpr size_t kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1; - -static const uint8_t* g_default_isolate_snapshot_data = nullptr; -static const uint8_t* g_default_isolate_snapshot_instructions = nullptr; -static bool g_service_isolate_initialized = false; -static ServiceIsolateHook g_service_isolate_hook = nullptr; -static RegisterNativeServiceProtocolExtensionHook - g_register_native_service_protocol_extensions_hook = nullptr; - -// Kernel representation of core dart libraries(loaded from platform.dill). -// TODO(aam): This (and platform_data below) have to be released when engine -// gets torn down. At that point we could also call Dart_Cleanup to complete -// Dart VM cleanup. -static void* kernel_platform = nullptr; -// Bytes actually read from platform.dill that are referenced by kernel_platform -static std::vector platform_data; - -void IsolateShutdownCallback(void* callback_data) { - if (tonic::DartStickyError::IsSet()) { - tonic::DartApiScope api_scope; - FXL_LOG(ERROR) << "Isolate " << tonic::StdStringFromDart(Dart_DebugName()) - << " exited with an error"; - Dart_Handle sticky_error = Dart_GetStickyError(); - FXL_CHECK(LogIfError(sticky_error)); - } - - UIDartState* dart_state = static_cast(callback_data); - // If the isolate that's shutting down is the main one, tell the higher layers - // of the stack. - if ((dart_state != NULL) && dart_state->is_controller_state()) { - dart_state->set_shutting_down(true); - if (dart_state->isolate_client()) { - dart_state->isolate_client()->DidShutdownMainIsolate(); - } - } -} - -// The cleanup callback frees the DartState object. -void IsolateCleanupCallback(void* callback_data) { - UIDartState* dart_state = static_cast(callback_data); - delete dart_state; -} - -bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) { - if (strncmp(source_url, kFileUriPrefix, kFileUriPrefixLength) != 0u) { - // Assume modified. - return true; - } - - const char* path = source_url + kFileUriPrefixLength; - struct stat info; - if (stat(path, &info) < 0) - return true; - - // If st_mtime is zero, it's more likely that the file system doesn't support - // mtime than that the file was actually modified in the 1970s. - if (!info.st_mtime) - return true; - - // It's very unclear what time bases we're with here. The Dart API doesn't - // document the time base for since_ms. Reading the code, the value varies by - // platform, with a typical source being something like gettimeofday. - // - // We add one to st_mtime because st_mtime has less precision than since_ms - // and we want to treat the file as modified if the since time is between - // ticks of the mtime. - fxl::TimeDelta mtime = fxl::TimeDelta::FromSeconds(info.st_mtime + 1); - fxl::TimeDelta since = fxl::TimeDelta::FromMilliseconds(since_ms); - - return mtime > since; -} - -void ThreadExitCallback() {} - -bool IsServiceIsolateURL(const char* url_name) { - return url_name != nullptr && - std::string(url_name) == DART_VM_SERVICE_ISOLATE_NAME; -} - -static bool StringEndsWith(const std::string& string, - const std::string& ending) { - if (ending.size() > string.size()) - return false; - - return string.compare(string.size() - ending.size(), ending.size(), ending) == - 0; -} - -static void ReleaseFetchedBytes(uint8_t* buffer) { - free(buffer); -} - -Dart_Isolate ServiceIsolateCreateCallback(const char* script_uri, - Dart_IsolateFlags* flags, - char** error) { -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE - // No VM-service in release mode. - return nullptr; -#else // FLUTTER_RUNTIME_MODE - UIDartState* dart_state = new UIDartState(nullptr, nullptr); - - bool is_running_from_kernel = GetKernelPlatformBinary() != nullptr; - - flags->load_vmservice_library = true; - Dart_Isolate isolate = - is_running_from_kernel - ? Dart_CreateIsolateFromKernel( - script_uri, "main", kernel_platform, flags, - static_cast(dart_state), error) - : Dart_CreateIsolate( - script_uri, "main", g_default_isolate_snapshot_data, - g_default_isolate_snapshot_instructions, flags, - static_cast(dart_state), error); - - FXL_CHECK(isolate) << error; - dart_state->set_debug_name_prefix(script_uri); - dart_state->SetIsolate(isolate); - FXL_CHECK(Dart_IsServiceIsolate(isolate)); - FXL_CHECK(!LogIfError( - Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); - { - tonic::DartApiScope dart_api_scope; - DartIO::InitForIsolate(); - DartUI::InitForIsolate(); - DartRuntimeHooks::Install(DartRuntimeHooks::SecondaryIsolate, script_uri); - const Settings& settings = Settings::Get(); - if (settings.enable_observatory) { - std::string ip = settings.ipv6 ? "::1" : "127.0.0.1"; - const intptr_t port = settings.observatory_port; - const bool disable_websocket_origin_check = false; - const bool service_isolate_booted = DartServiceIsolate::Startup( - ip, port, tonic::DartState::HandleLibraryTag, - !IsRunningPrecompiledCode() && !is_running_from_kernel, - disable_websocket_origin_check, error); - FXL_CHECK(service_isolate_booted) << error; - } - - if (g_service_isolate_hook) - g_service_isolate_hook(IsRunningPrecompiledCode()); - } - Dart_ExitIsolate(); - - g_service_isolate_initialized = true; - // Register any native service protocol extensions. - if (g_register_native_service_protocol_extensions_hook) { - g_register_native_service_protocol_extensions_hook( - IsRunningPrecompiledCode()); - } - return isolate; -#endif // FLUTTER_RUNTIME_MODE -} - -static bool GetAssetAsBuffer( - const std::string& name, - std::vector* data, - fxl::RefPtr& directory_asset_bundle, - fxl::RefPtr& asset_store) { - return (directory_asset_bundle && - directory_asset_bundle->GetAsBuffer(name, data)) || - (asset_store && asset_store->GetAsBuffer(name, data)); -} - -Dart_Isolate IsolateCreateCallback(const char* script_uri, - const char* main, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - void* callback_data, - char** error) { - TRACE_EVENT0("flutter", __func__); - - if (IsServiceIsolateURL(script_uri)) { - return ServiceIsolateCreateCallback(script_uri, flags, error); - } - - std::string entry_uri = script_uri; - // Are we running from a Dart source file? - const bool running_from_source = StringEndsWith(entry_uri, ".dart"); - - std::vector kernel_data; - std::vector snapshot_data; - std::string entry_path; - if (!IsRunningPrecompiledCode()) { - // Check that the entry script URI starts with file:// - if (entry_uri.find(kFileUriPrefix) != 0u) { - *error = strdup("Isolates must use file:// URIs"); - return nullptr; - } - // Entry script path (file:// is stripped). - entry_path = std::string(script_uri + strlen(kFileUriPrefix)); - if (StringEndsWith(entry_path, ".dill")) { - // Load the kernel from the script URI. - if (!files::ReadFileToVector(entry_path, &kernel_data)) { - FXL_LOG(ERROR) << "Failed to load kernel"; - } - } else if (!running_from_source) { - // Attempt to copy the snapshot or kernel from the asset bundle. - const std::string& bundle_path = entry_path; - - struct stat stat_result = {}; - if (::stat(bundle_path.c_str(), &stat_result) == 0) { - fxl::RefPtr directory_asset_bundle; - // TODO(zarah): Remove usage of zip_asset_store once app.flx is removed. - fxl::RefPtr zip_asset_store; - // bundle_path is either the path to app.flx or the flutter assets - // directory. - std::string flx_path = bundle_path; - if (S_ISDIR(stat_result.st_mode)) { - directory_asset_bundle = - fxl::MakeRefCounted(bundle_path); - flx_path = files::GetDirectoryName(bundle_path) + "/app.flx"; - } - - if (access(flx_path.c_str(), R_OK) == 0) { - zip_asset_store = fxl::MakeRefCounted( - GetUnzipperProviderForPath(flx_path)); - } - GetAssetAsBuffer(kKernelAssetKey, &kernel_data, directory_asset_bundle, - zip_asset_store); - GetAssetAsBuffer(kSnapshotAssetKey, &snapshot_data, - directory_asset_bundle, zip_asset_store); - } - } - } - - UIDartState* parent_dart_state = static_cast(callback_data); - UIDartState* dart_state = parent_dart_state->CreateForChildIsolate(); - - Dart_Isolate isolate = - kernel_platform != nullptr - ? Dart_CreateIsolateFromKernel(script_uri, main, kernel_platform, - nullptr /* flags */, dart_state, error) - : Dart_CreateIsolate(script_uri, main, - g_default_isolate_snapshot_data, - g_default_isolate_snapshot_instructions, nullptr, - dart_state, error); - FXL_CHECK(isolate) << error; - dart_state->set_debug_name_prefix(script_uri); - dart_state->SetIsolate(isolate); - FXL_CHECK(!LogIfError( - Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); - - { - tonic::DartApiScope dart_api_scope; - DartIO::InitForIsolate(); - DartUI::InitForIsolate(); - DartRuntimeHooks::Install(DartRuntimeHooks::SecondaryIsolate, script_uri); - - std::unique_ptr ui_class_provider( - new DartClassProvider(dart_state, "dart:ui")); - dart_state->class_library().add_provider("ui", - std::move(ui_class_provider)); - - if (!kernel_data.empty()) { - // We are running kernel code. - FXL_CHECK(!LogIfError(Dart_LoadScriptFromKernel(kernel_data.data(), - kernel_data.size()))); - } else if (!snapshot_data.empty()) { - // We are running from a script snapshot. - FXL_CHECK(!LogIfError(Dart_LoadScriptFromSnapshot(snapshot_data.data(), - snapshot_data.size()))); - } else if (running_from_source) { - // We are running from source. - // Forward the .packages configuration from the parent isolate to the - // child isolate. - tonic::FileLoader& parent_loader = parent_dart_state->file_loader(); - const std::string& packages = parent_loader.packages(); - tonic::FileLoader& loader = dart_state->file_loader(); - if (!packages.empty() && !loader.LoadPackagesMap(packages)) { - FXL_LOG(WARNING) << "Failed to load package map: " << packages; - } - // Load the script. - FXL_CHECK(!LogIfError(loader.LoadScript(entry_path))); - } - - dart_state->isolate_client()->DidCreateSecondaryIsolate(isolate); - } - - Dart_ExitIsolate(); - - FXL_CHECK(Dart_IsolateMakeRunnable(isolate)); - return isolate; -} - -Dart_Handle GetVMServiceAssetsArchiveCallback() { -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE - return nullptr; -#elif OS(FUCHSIA) - std::vector observatory_assets_archive; - if (!files::ReadFileToVector("pkg/data/observatory.tar", - &observatory_assets_archive)) { - FXL_LOG(ERROR) << "Fail to load Observatory archive"; - return nullptr; - } - return tonic::DartConverter::ToDart( - observatory_assets_archive.data(), - observatory_assets_archive.size()); -#else - return tonic::DartConverter::ToDart( - ::dart::observatory::observatory_assets_archive, - ::dart::observatory::observatory_assets_archive_len); -#endif -} - -static const char kStdoutStreamId[] = "Stdout"; -static const char kStderrStreamId[] = "Stderr"; - -static bool ServiceStreamListenCallback(const char* stream_id) { - if (strcmp(stream_id, kStdoutStreamId) == 0) { - dart::bin::SetCaptureStdout(true); - return true; - } else if (strcmp(stream_id, kStderrStreamId) == 0) { - dart::bin::SetCaptureStderr(true); - return true; - } - return false; -} - -static void ServiceStreamCancelCallback(const char* stream_id) { - if (strcmp(stream_id, kStdoutStreamId) == 0) { - dart::bin::SetCaptureStdout(false); - } else if (strcmp(stream_id, kStderrStreamId) == 0) { - dart::bin::SetCaptureStderr(false); - } -} - -} // namespace - -bool IsRunningPrecompiledCode() { - return Dart_IsPrecompiledRuntime(); -} - -EmbedderTracingCallbacks* g_tracing_callbacks = nullptr; - -EmbedderTracingCallbacks::EmbedderTracingCallbacks( - EmbedderTracingCallback start, - EmbedderTracingCallback stop) - : start_tracing_callback(start), stop_tracing_callback(stop) {} - -void SetEmbedderTracingCallbacks( - std::unique_ptr callbacks) { - g_tracing_callbacks = callbacks.release(); -} - -static void EmbedderTimelineStartRecording() { - if (g_tracing_callbacks) - g_tracing_callbacks->start_tracing_callback(); -} - -static void EmbedderTimelineStopRecording() { - if (g_tracing_callbacks) - g_tracing_callbacks->stop_tracing_callback(); -} - -static std::vector ProfilingFlags(bool enable_profiling) { -// Disable Dart's built in profiler when building a debug build. This -// works around a race condition that would sometimes stop a crash's -// stack trace from being printed on Android. -#ifndef NDEBUG - enable_profiling = false; -#endif - - // We want to disable profiling by default because it overwhelms LLDB. But - // the VM enables the same by default. In either case, we have some profiling - // flags. - if (enable_profiling) { - return { - // This is the default. But just be explicit. - "--profiler", - // This instructs the profiler to walk C++ frames, and to include - // them in the profile. - "--profile-vm"}; - } else { - return {"--no-profiler"}; - } -} - -void SetServiceIsolateHook(ServiceIsolateHook hook) { - FXL_CHECK(!g_service_isolate_initialized); - g_service_isolate_hook = hook; -} - -void SetRegisterNativeServiceProtocolExtensionHook( - RegisterNativeServiceProtocolExtensionHook hook) { - FXL_CHECK(!g_service_isolate_initialized); - g_register_native_service_protocol_extensions_hook = hook; -} - -void PushBackAll(std::vector* args, - const char** argv, - size_t argc) { - for (size_t i = 0; i < argc; ++i) { - args->push_back(argv[i]); - } -} - -static void EmbedderInformationCallback(Dart_EmbedderInformation* info) { - info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION; - dart::bin::GetIOEmbedderInformation(info); - info->name = "Flutter"; -} - -void* GetKernelPlatformBinary() { - return kernel_platform; -} - -void InitDartVM(const uint8_t* vm_snapshot_data, - const uint8_t* vm_snapshot_instructions, - const uint8_t* default_isolate_snapshot_data, - const uint8_t* default_isolate_snapshot_instructions, - const std::string& bundle_path) { - TRACE_EVENT0("flutter", __func__); - - g_default_isolate_snapshot_data = default_isolate_snapshot_data; - g_default_isolate_snapshot_instructions = - default_isolate_snapshot_instructions; - - const Settings& settings = Settings::Get(); - - { - TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo"); - dart::bin::BootstrapDartIo(); - - if (!settings.temp_directory_path.empty()) { - dart::bin::SetSystemTempDirectory(settings.temp_directory_path.c_str()); - } - } - - std::vector args; - - // Instruct the VM to ignore unrecognized flags. - // There is a lot of diversity in a lot of combinations when it - // comes to the arguments the VM supports. And, if the VM comes across a flag - // it does not recognize, it exits immediately. - args.push_back("--ignore-unrecognized-flags"); - - for (const auto& profiler_flag : - ProfilingFlags(settings.enable_dart_profiling)) { - args.push_back(profiler_flag); - } - - PushBackAll(&args, kDartLanguageArgs, arraysize(kDartLanguageArgs)); - - if (IsRunningPrecompiledCode()) { - PushBackAll(&args, kDartPrecompilationArgs, - arraysize(kDartPrecompilationArgs)); - } - -#if defined(OS_FUCHSIA) -#if defined(NDEBUG) - // Do not enable checked mode for Fuchsia release builds - // TODO(mikejurka): remove this once precompiled code is working on Fuchsia - const bool use_checked_mode = false; -#else // !defined(NDEBUG) - const bool use_checked_mode = true; -#endif // !defined(NDEBUG) -#else // !defined(OS_FUCHSIA) - // Enable checked mode if we are not running precompiled code. We run non- - // precompiled code only in the debug product mode. - const bool use_checked_mode = - !IsRunningPrecompiledCode() && !settings.dart_non_checked_mode; -#endif // !defined(OS_FUCHSIA) - -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - // Debug mode uses the JIT, disable code page write protection to avoid - // memory page protection changes before and after every compilation. - PushBackAll(&args, kDartWriteProtectCodeArgs, - arraysize(kDartWriteProtectCodeArgs)); -#endif - - if (settings.start_paused) - PushBackAll(&args, kDartStartPausedArgs, arraysize(kDartStartPausedArgs)); - - if (settings.endless_trace_buffer || settings.trace_startup) { - // If we are tracing startup, make sure the trace buffer is endless so we - // don't lose early traces. - PushBackAll(&args, kDartEndlessTraceBufferArgs, - arraysize(kDartEndlessTraceBufferArgs)); - } - - if (settings.trace_startup) { - PushBackAll(&args, kDartTraceStartupArgs, arraysize(kDartTraceStartupArgs)); - } - -#if defined(OS_FUCHSIA) - PushBackAll(&args, kDartFuchsiaTraceArgs, arraysize(kDartFuchsiaTraceArgs)); -#endif - - if (!bundle_path.empty()) { - fxl::RefPtr directory_asset_bundle = - fxl::MakeRefCounted( - std::move(bundle_path)); - directory_asset_bundle->GetAsBuffer(kPlatformKernelAssetKey, - &platform_data); - if (!platform_data.empty()) { - uint8_t* kernel_buf = static_cast(malloc(platform_data.size())); - memcpy(kernel_buf, platform_data.data(), platform_data.size()); - kernel_platform = Dart_ReadKernelBinary(kernel_buf, platform_data.size(), - ReleaseFetchedBytes); - FXL_DCHECK(kernel_platform != nullptr); - } - } - if ((kernel_platform != nullptr) || - Dart_IsDart2Snapshot(g_default_isolate_snapshot_data)) { - // The presence of the kernel platform file or a snapshot that was generated - // for Dart2 indicates we are running in preview-dart-2 mode and in this - // mode enable strong mode options by default. - // Note: When we start using core snapshots instead of the platform file - // in the engine just sniffing the snapshot file should be sufficient. - PushBackAll(&args, kDartStrongModeArgs, arraysize(kDartStrongModeArgs)); - // In addition if we are running in debug mode we also enable asserts. - if (use_checked_mode) { - PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); - } - } else if (use_checked_mode) { - // In non preview-dart-2 mode we enable checked mode and asserts if - // we are running in debug mode. - PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); - PushBackAll(&args, kDartCheckedModeArgs, arraysize(kDartCheckedModeArgs)); - } - - for (size_t i = 0; i < settings.dart_flags.size(); i++) - args.push_back(settings.dart_flags[i].c_str()); - - FXL_CHECK(Dart_SetVMFlags(args.size(), args.data())); - - DartUI::InitForGlobal(); - - // Setup embedder tracing hooks. To avoid data races, it is recommended that - // these hooks be installed before the DartInitialize, so do that setup now. - Dart_SetEmbedderTimelineCallbacks(&EmbedderTimelineStartRecording, - &EmbedderTimelineStopRecording); - - Dart_SetFileModifiedCallback(&DartFileModifiedCallback); - - { - TRACE_EVENT0("flutter", "Dart_Initialize"); - Dart_InitializeParams params = {}; - params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; - params.vm_snapshot_data = vm_snapshot_data; - params.vm_snapshot_instructions = vm_snapshot_instructions; - params.create = IsolateCreateCallback; - params.shutdown = IsolateShutdownCallback; - params.cleanup = IsolateCleanupCallback; - params.thread_exit = ThreadExitCallback; - params.get_service_assets = GetVMServiceAssetsArchiveCallback; - params.entropy_source = DartIO::EntropySource; - char* init_error = Dart_Initialize(¶ms); - if (init_error != nullptr) - FXL_LOG(FATAL) << "Error while initializing the Dart VM: " << init_error; - free(init_error); - - // Send the earliest available timestamp in the application lifecycle to - // timeline. The difference between this timestamp and the time we render - // the very first frame gives us a good idea about Flutter's startup time. - // Use a duration event so about:tracing will consider this event when - // deciding the earliest event to use as time 0. - if (blink::engine_main_enter_ts != 0) { - Dart_TimelineEvent("FlutterEngineMainEnter", // label - blink::engine_main_enter_ts, // timestamp0 - blink::engine_main_enter_ts, // timestamp1_or_async_id - Dart_Timeline_Event_Duration, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values - ); - } - } - - // Allow streaming of stdout and stderr by the Dart vm. - Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback, - &ServiceStreamCancelCallback); - - Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback); -} - -} // namespace blink diff --git a/runtime/dart_init.h b/runtime/dart_init.h deleted file mode 100644 index 99c8fe89137e3..0000000000000 --- a/runtime/dart_init.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2015 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_RUNTIME_DART_INIT_H_ -#define FLUTTER_RUNTIME_DART_INIT_H_ - -#include "lib/fxl/build_config.h" -#include "lib/fxl/functional/closure.h" -#include "third_party/dart/runtime/include/dart_api.h" - -#include -#include -#include - -namespace blink { - -// Name of the kernel blob asset within the asset directory. -extern const char kKernelAssetKey[]; - -// Name of the snapshot blob asset within the asset directory. -extern const char kSnapshotAssetKey[]; - -// Name of the platform kernel blob asset within the asset directory. -extern const char kPlatformKernelAssetKey[]; - -bool IsRunningPrecompiledCode(); - -using EmbedderTracingCallback = fxl::Closure; - -typedef void (*ServiceIsolateHook)(bool); -typedef void (*RegisterNativeServiceProtocolExtensionHook)(bool); - -struct EmbedderTracingCallbacks { - EmbedderTracingCallback start_tracing_callback; - EmbedderTracingCallback stop_tracing_callback; - - EmbedderTracingCallbacks(EmbedderTracingCallback start, - EmbedderTracingCallback stop); -}; - -void InitDartVM(const uint8_t* vm_snapshot_data, - const uint8_t* vm_snapshot_instructions, - const uint8_t* default_isolate_snapshot_data, - const uint8_t* default_isolate_snapshot_instructions, - const std::string& bundle_path); - -void* GetKernelPlatformBinary(); - -void SetEmbedderTracingCallbacks( - std::unique_ptr callbacks); - -// Provide a function that will be called during initialization of the -// service isolate. -void SetServiceIsolateHook(ServiceIsolateHook hook); - -// Provide a function that will be called to register native service protocol -// extensions. -void SetRegisterNativeServiceProtocolExtensionHook( - RegisterNativeServiceProtocolExtensionHook hook); - -} // namespace blink - -#endif // FLUTTER_RUNTIME_DART_INIT_H_ diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc new file mode 100644 index 0000000000000..c5fd770b1b40c --- /dev/null +++ b/runtime/dart_isolate.cc @@ -0,0 +1,715 @@ +// 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/runtime/dart_isolate.h" + +#include +#include + +#include "flutter/fml/trace_event.h" +#include "flutter/lib/io/dart_io.h" +#include "flutter/lib/ui/dart_runtime_hooks.h" +#include "flutter/lib/ui/dart_ui.h" +#include "flutter/runtime/dart_service_isolate.h" +#include "flutter/runtime/dart_vm.h" +#include "lib/fxl/files/path.h" +#include "lib/tonic/converter/dart_converter.h" +#include "lib/tonic/dart_class_library.h" +#include "lib/tonic/dart_class_provider.h" +#include "lib/tonic/dart_message_handler.h" +#include "lib/tonic/dart_state.h" +#include "lib/tonic/dart_sticky_error.h" +#include "lib/tonic/file_loader/file_loader.h" +#include "lib/tonic/scopes/dart_api_scope.h" +#include "lib/tonic/scopes/dart_isolate_scope.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +#ifdef ERROR +#undef ERROR +#endif + +namespace blink { + +fml::WeakPtr DartIsolate::CreateRootIsolate( + const DartVM* vm, + fxl::RefPtr isolate_snapshot, + TaskRunners task_runners, + std::unique_ptr window, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint, + Dart_IsolateFlags* flags) { + TRACE_EVENT0("flutter", "DartIsolate::CreateRootIsolate"); + Dart_Isolate vm_isolate = nullptr; + fml::WeakPtr embedder_isolate; + + char* error = nullptr; + + // Since this is the root isolate, we fake a parent embedder data object. We + // cannot use unique_ptr here because the destructor is private (since the + // isolate lifecycle is entirely managed by the VM). + auto root_embedder_data = std::make_unique( + vm, // VM + std::move(isolate_snapshot), // isolate snapshot + task_runners, // task runners + std::move(resource_context), // resource context + std::move(unref_queue), // skia unref queue + advisory_script_uri, // advisory URI + advisory_script_entrypoint // advisory entrypoint + ); + + std::tie(vm_isolate, embedder_isolate) = CreateDartVMAndEmbedderObjectPair( + advisory_script_uri.c_str(), // advisory script URI + advisory_script_entrypoint.c_str(), // advisory script entrypoint + nullptr, // package root + nullptr, // package config + flags, // flags + root_embedder_data.get(), // parent embedder data + true, // is root isolate + &error // error (out) + ); + + if (error != nullptr) { + free(error); + } + + if (vm_isolate == nullptr) { + return {}; + } + + if (embedder_isolate) { + // Only root isolates can interact with windows. + embedder_isolate->SetWindow(std::move(window)); + embedder_isolate->set_use_blink(vm->GetSettings().using_blink); + } + + return embedder_isolate; +} + +DartIsolate::DartIsolate(const DartVM* vm, + fxl::RefPtr isolate_snapshot, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint) + : UIDartState(std::move(task_runners), + vm->GetSettings().task_observer_add, + vm->GetSettings().task_observer_remove, + std::move(resource_context), + std::move(unref_queue), + advisory_script_uri, + advisory_script_entrypoint, + vm->GetSettings().log_tag), + vm_(vm), + isolate_snapshot_(std::move(isolate_snapshot)), + weak_factory_(this) { + FXL_DCHECK(isolate_snapshot_) << "Must contain a valid isolate snapshot."; + weak_prototype_ = weak_factory_.GetWeakPtr(); + + if (vm_ == nullptr) { + return; + } + + phase_ = Phase::Uninitialized; +} + +DartIsolate::~DartIsolate() = default; + +DartIsolate::Phase DartIsolate::GetPhase() const { + return phase_; +} + +const DartVM* DartIsolate::GetDartVM() const { + return vm_; +} + +bool DartIsolate::Initialize(Dart_Isolate dart_isolate, bool is_root_isolate) { + TRACE_EVENT0("flutter", "DartIsolate::Initialize"); + if (phase_ != Phase::Uninitialized) { + return false; + } + + if (dart_isolate == nullptr) { + return false; + } + + if (Dart_CurrentIsolate() != dart_isolate) { + return false; + } + + if (Dart_IsolateData(dart_isolate) != this) { + return false; + } + + // After this point, isolate scopes can be safely used. + SetIsolate(dart_isolate); + + // We are entering a new scope (for the first time since initialization) and + // we want to restore the current scope to null when we exit out of this + // method. This balances the implicit Dart_EnterIsolate call made by + // Dart_CreateIsolate (which calls the Initialize). + Dart_ExitIsolate(); + + tonic::DartIsolateScope scope(isolate()); + + if (is_root_isolate) { + if (auto task_runner = GetTaskRunners().GetUITaskRunner()) { + // Isolates may not have any particular thread affinity. Only initialize + // the message handler if a task runner is explicitly specified. + message_handler().Initialize(task_runner); + } + } + + if (tonic::LogIfError( + Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))) { + return false; + } + + if (!UpdateThreadPoolNames()) { + return false; + } + + phase_ = Phase::Initialized; + return true; +} + +// Updating thread names here does not change the underlying OS thread names. +// Instead, this is just additional metadata for the Observatory to show the +// thread name of the isolate. +bool DartIsolate::UpdateThreadPoolNames() const { + // TODO(chinmaygarde): This implementation does not account for multiple + // shells sharing the same (or subset of) threads. + const auto& task_runners = GetTaskRunners(); + + if (auto task_runner = task_runners.GetGPUTaskRunner()) { + task_runner->PostTask( + [label = task_runners.GetLabel() + std::string{".gpu"}]() { + Dart_SetThreadName(label.c_str()); + }); + } + + if (auto task_runner = task_runners.GetUITaskRunner()) { + task_runner->PostTask( + [label = task_runners.GetLabel() + std::string{".ui"}]() { + Dart_SetThreadName(label.c_str()); + }); + } + + if (auto task_runner = task_runners.GetIOTaskRunner()) { + task_runner->PostTask( + [label = task_runners.GetLabel() + std::string{".io"}]() { + Dart_SetThreadName(label.c_str()); + }); + } + + if (auto task_runner = task_runners.GetPlatformTaskRunner()) { + task_runner->PostTask( + [label = task_runners.GetLabel() + std::string{".platform"}]() { + Dart_SetThreadName(label.c_str()); + }); + } + + return true; +} + +bool DartIsolate::LoadLibraries() { + TRACE_EVENT0("flutter", "DartIsolate::LoadLibraries"); + if (phase_ != Phase::Initialized) { + return false; + } + + tonic::DartState::Scope scope(this); + + DartIO::InitForIsolate(); + + DartUI::InitForIsolate(); + + const bool is_service_isolate = Dart_IsServiceIsolate(isolate()); + + DartRuntimeHooks::Install(is_service_isolate + ? DartRuntimeHooks::SecondaryIsolate + : DartRuntimeHooks::MainIsolate, + GetAdvisoryScriptURI()); + + if (!is_service_isolate) { + class_library().add_provider( + "ui", std::make_unique(this, "dart:ui")); + } + + phase_ = Phase::LibrariesSetup; + return true; +} + +bool DartIsolate::PrepareForRunningFromPrecompiledCode() { + TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromPrecompiledCode"); + if (phase_ != Phase::LibrariesSetup) { + return false; + } + + if (!DartVM::IsRunningPrecompiledCode()) { + return false; + } + + tonic::DartState::Scope scope(this); + + if (Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + if (!MarkIsolateRunnable()) { + return false; + } + + phase_ = Phase::Ready; + return true; +} + +static bool LoadScriptSnapshot(std::unique_ptr mapping) { + if (tonic::LogIfError(Dart_LoadScriptFromSnapshot(mapping->GetMapping(), + mapping->GetSize()))) { + return false; + } + return true; +} + +static bool LoadKernelSnapshot(std::unique_ptr mapping) { + if (tonic::LogIfError(Dart_LoadScriptFromKernel(mapping->GetMapping(), + mapping->GetSize()))) { + return false; + } + + return true; +} + +static bool LoadSnapshot(std::unique_ptr mapping, + bool is_kernel) { + if (is_kernel) { + return LoadKernelSnapshot(std::move(mapping)); + } else { + return LoadScriptSnapshot(std::move(mapping)); + } + return false; +} + +FXL_WARN_UNUSED_RESULT +bool DartIsolate::PrepareForRunningFromSnapshot( + std::unique_ptr mapping) { + TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromSnapshot"); + if (phase_ != Phase::LibrariesSetup) { + return false; + } + + if (DartVM::IsRunningPrecompiledCode()) { + return false; + } + + if (!mapping || mapping->GetSize() == 0) { + return false; + } + + tonic::DartState::Scope scope(this); + + if (!Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + if (!LoadSnapshot(std::move(mapping), vm_->GetPlatformKernel() != nullptr)) { + return false; + } + + if (Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + if (!MarkIsolateRunnable()) { + return false; + } + + phase_ = Phase::Ready; + return true; +} + +static bool FileNameIsDill(const std::string& name) { + const std::string suffix = ".dill"; + + if (name.size() < suffix.size()) { + return false; + } + + if (name.rfind(suffix, name.size()) == name.size() - suffix.size()) { + return true; + } + return false; +} + +bool DartIsolate::PrepareForRunningFromSource( + const std::string& main_source_file, + const std::string& packages) { + TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromSource"); + if (phase_ != Phase::LibrariesSetup) { + return false; + } + + if (DartVM::IsRunningPrecompiledCode()) { + return false; + } + + if (main_source_file.empty()) { + return false; + } + + tonic::DartState::Scope scope(this); + + if (!Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + auto& loader = file_loader(); + + if (!packages.empty()) { + auto packages_absolute_path = files::AbsolutePath(packages); + FXL_DLOG(INFO) << "Loading from packages: " << packages_absolute_path; + if (!loader.LoadPackagesMap(packages_absolute_path)) { + return false; + } + } + + auto main_source_absolute_path = files::AbsolutePath(main_source_file); + FXL_DLOG(INFO) << "Loading from source: " << main_source_absolute_path; + + // The "source" file may be a ".dill" file. + if (FileNameIsDill(main_source_absolute_path)) { + auto mapping = + std::make_unique(main_source_absolute_path, false); + if (mapping == nullptr) { + return false; + } + if (!LoadKernelSnapshot(std::move(mapping))) { + return false; + } + } else { + if (tonic::LogIfError(loader.LoadScript(main_source_absolute_path))) { + return false; + } + } + + if (Dart_IsNull(Dart_RootLibrary())) { + return false; + } + + if (!MarkIsolateRunnable()) { + return false; + } + + phase_ = Phase::Ready; + return true; +} + +bool DartIsolate::MarkIsolateRunnable() { + TRACE_EVENT0("flutter", "DartIsolate::MarkIsolateRunnable"); + if (phase_ != Phase::LibrariesSetup) { + return false; + } + + // This function may only be called from an active isolate scope. + if (Dart_CurrentIsolate() != isolate()) { + return false; + } + + // There must be no current isolate to mark an isolate as being runnable. + Dart_ExitIsolate(); + + if (!Dart_IsolateMakeRunnable(isolate())) { + // Failed. Restore the isolate. + Dart_EnterIsolate(isolate()); + return false; + } + // Success. Restore the isolate. + Dart_EnterIsolate(isolate()); + return true; +} + +FXL_WARN_UNUSED_RESULT +bool DartIsolate::Run(const std::string& entrypoint_name) { + TRACE_EVENT0("flutter", "DartIsolate::Run"); + if (phase_ != Phase::Ready) { + return false; + } + + tonic::DartState::Scope scope(this); + + Dart_Handle entrypoint = Dart_GetClosure( + Dart_RootLibrary(), tonic::ToDart(entrypoint_name.c_str())); + if (tonic::LogIfError(entrypoint)) { + return false; + } + + Dart_Handle isolate_lib = Dart_LookupLibrary(tonic::ToDart("dart:isolate")); + if (tonic::LogIfError(isolate_lib)) { + return false; + } + + Dart_Handle isolate_args[] = { + entrypoint, + Dart_Null(), + }; + + if (tonic::LogIfError(Dart_Invoke( + isolate_lib, tonic::ToDart("_startMainIsolate"), + sizeof(isolate_args) / sizeof(isolate_args[0]), isolate_args))) { + return false; + } + + phase_ = Phase::Running; + return true; +} + +bool DartIsolate::Shutdown() { + TRACE_EVENT0("flutter", "DartIsolate::Shutdown"); + // This call may be re-entrant since Dart_ShutdownIsolate can invoke the + // cleanup callback which deletes the embedder side object of the dart isolate + // (a.k.a. this). + if (phase_ == Phase::Shutdown) { + return false; + } + phase_ = Phase::Shutdown; + Dart_Isolate vm_isolate = isolate(); + // The isolate can be nullptr if this instance is the stub isolate data used + // during root isolate creation. + if (vm_isolate != nullptr) { + // We need to enter the isolate because Dart_ShutdownIsolate does not take + // the isolate to shutdown as a parameter. + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); + Dart_EnterIsolate(vm_isolate); + Dart_ShutdownIsolate(); + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); + } + return true; +} + +static Dart_Isolate DartCreateAndStartServiceIsolate( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + char** error) { + auto vm = DartVM::ForProcessIfInitialized(); + + if (!vm) { + *error = strdup( + "Could not resolve the VM when attempting to create the service " + "isolate."); + return nullptr; + } + + const auto& settings = vm->GetSettings(); + + if (!settings.enable_observatory) { + FXL_DLOG(INFO) << "Observatory is disabled."; + return nullptr; + } + + blink::TaskRunners null_task_runners( + "io.flutter." DART_VM_SERVICE_ISOLATE_NAME, nullptr, nullptr, nullptr, + nullptr); + + flags->load_vmservice_library = true; + + auto service_isolate = DartIsolate::CreateRootIsolate( + vm.get(), // vm + vm->GetIsolateSnapshot(), // isolate snapshot + null_task_runners, // task runners + nullptr, // window + {}, // resource context + {}, // unref queue + advisory_script_uri == nullptr ? "" : advisory_script_uri, // script uri + advisory_script_entrypoint == nullptr + ? "" + : advisory_script_entrypoint, // script entrypoint + flags // flags + ); + + if (!service_isolate) { + *error = strdup("Could not create the service isolate."); + FXL_DLOG(ERROR) << *error; + return nullptr; + } + + // The engine never holds a strong reference to the VM service isolate. Since + // we are about to lose our last weak reference to it, start the VM service + // while we have this reference. + + const bool running_from_sources = + !DartVM::IsRunningPrecompiledCode() && vm->GetPlatformKernel() == nullptr; + + tonic::DartState::Scope scope(service_isolate.get()); + if (!DartServiceIsolate::Startup( + settings.ipv6 ? "::1" : "127.0.0.1", // server IP address + settings.observatory_port, // server observatory port + tonic::DartState::HandleLibraryTag, // embedder library tag handler + running_from_sources, // running from source code + false, // disable websocket origin check + error // error (out) + )) { + // Error is populated by call to startup. + FXL_DLOG(ERROR) << *error; + return nullptr; + } + + vm->GetServiceProtocol().ToggleHooks(true); + + return service_isolate->isolate(); +} + +// |Dart_IsolateCreateCallback| +Dart_Isolate DartIsolate::DartIsolateCreateCallback( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + DartIsolate* parent_embedder_isolate, + char** error) { + if (parent_embedder_isolate == nullptr && + strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) { + // The VM attempts to start the VM service for us on |Dart_Initialize|. In + // such a case, the callback data will be null and the script URI will be + // DART_VM_SERVICE_ISOLATE_NAME. In such cases, we just create the service + // isolate like normal but dont hold a reference to it at all. We also start + // this isolate since we will never again reference it from the engine. + return DartCreateAndStartServiceIsolate(advisory_script_uri, // + advisory_script_entrypoint, // + package_root, // + package_config, // + flags, // + error // + ); + } + + return CreateDartVMAndEmbedderObjectPair( + advisory_script_uri, // URI + advisory_script_entrypoint, // entrypoint + package_root, // package root + package_config, // package config + flags, // isolate flags + parent_embedder_isolate, // embedder data + false, // is root isolate + error // error + ) + .first; +} + +std::pair> +DartIsolate::CreateDartVMAndEmbedderObjectPair( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + DartIsolate* parent_embedder_isolate, + bool is_root_isolate, + char** error) { + TRACE_EVENT0("flutter", "DartIsolate::CreateDartVMAndEmbedderObjectPair"); + if (parent_embedder_isolate == nullptr || + parent_embedder_isolate->GetDartVM() == nullptr) { + *error = + strdup("Parent isolate did not have embedder specific callback data."); + FXL_DLOG(ERROR) << *error; + return {nullptr, {}}; + } + + const DartVM* vm = parent_embedder_isolate->GetDartVM(); + + // Create the native object on the embedder side. This object is deleted in + // the cleanup callback. + auto embedder_isolate = std::make_unique( + vm, // + parent_embedder_isolate->GetIsolateSnapshot(), // + parent_embedder_isolate->GetTaskRunners(), // + parent_embedder_isolate->GetResourceContext(), // + parent_embedder_isolate->GetSkiaUnrefQueue(), // + advisory_script_uri, // + advisory_script_entrypoint // + ); + + // Create the Dart VM isolate and give it the embedder object as the baton. + Dart_Isolate isolate = + vm->GetPlatformKernel() != nullptr + ? Dart_CreateIsolateFromKernel(advisory_script_uri, // + advisory_script_entrypoint, // + vm->GetPlatformKernel(), // + flags, // + embedder_isolate.get(), // + error // + ) + : Dart_CreateIsolate(advisory_script_uri, // + advisory_script_entrypoint, // + embedder_isolate->GetIsolateSnapshot() + ->GetData() + ->GetSnapshotPointer(), // + embedder_isolate->GetIsolateSnapshot() + ->GetInstructionsIfPresent(), // + flags, // + embedder_isolate.get(), // + error // + ); + + if (isolate == nullptr) { + FXL_DLOG(ERROR) << *error; + return {nullptr, {}}; + } + + if (!embedder_isolate->Initialize(isolate, is_root_isolate)) { + *error = strdup("Embedder could not initialize the Dart isolate."); + FXL_DLOG(ERROR) << *error; + return {nullptr, {}}; + } + + if (!embedder_isolate->LoadLibraries()) { + *error = + strdup("Embedder could not load libraries in the new Dart isolate."); + FXL_DLOG(ERROR) << *error; + return {nullptr, {}}; + } + + // The ownership of the embedder object is controlled by the Dart VM. So the + // only reference returned to the caller is weak. + return {isolate, embedder_isolate.release()->GetWeakIsolatePtr()}; +} + +// |Dart_IsolateShutdownCallback| +void DartIsolate::DartIsolateShutdownCallback(DartIsolate* embedder_isolate) { + if (!tonic::DartStickyError::IsSet()) { + return; + } + + tonic::DartApiScope api_scope; + FXL_LOG(ERROR) << "Isolate " << tonic::StdStringFromDart(Dart_DebugName()) + << " exited with an error"; + Dart_Handle sticky_error = Dart_GetStickyError(); + FXL_CHECK(tonic::LogIfError(sticky_error)); +} + +// |Dart_IsolateCleanupCallback| +void DartIsolate::DartIsolateCleanupCallback(DartIsolate* embedder_isolate) { + delete embedder_isolate; +} + +fxl::RefPtr DartIsolate::GetIsolateSnapshot() const { + return isolate_snapshot_; +} + +fml::WeakPtr DartIsolate::GetWeakIsolatePtr() const { + return weak_prototype_; +} + +void DartIsolate::AddIsolateShutdownCallback(fxl::Closure closure) { + shutdown_callbacks_.emplace_back( + std::make_unique(std::move(closure))); +} + +} // namespace blink diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h new file mode 100644 index 0000000000000..13d573ebe333f --- /dev/null +++ b/runtime/dart_isolate.h @@ -0,0 +1,152 @@ +// 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_RUNTIME_DART_ISOLATE_H_ +#define FLUTTER_RUNTIME_DART_ISOLATE_H_ + +#include +#include + +#include "flutter/common/task_runners.h" +#include "flutter/fml/mapping.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/window.h" +#include "flutter/runtime/dart_snapshot.h" +#include "lib/fxl/compiler_specific.h" +#include "lib/fxl/macros.h" +#include "lib/tonic/dart_state.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace blink { +class DartVM; + +class DartIsolate : public UIDartState { + public: + enum class Phase { + Unknown, + Uninitialized, + Initialized, + LibrariesSetup, + Ready, + Running, + Shutdown, + }; + + // The root isolate of a Flutter application is special because it gets Window + // bindings. From the VM's perspective, this isolate is not special in any + // way. + static fml::WeakPtr CreateRootIsolate( + const DartVM* vm, + fxl::RefPtr isolate_snapshot, + TaskRunners task_runners, + std::unique_ptr window, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri = "main.dart", + std::string advisory_script_entrypoint = "main", + Dart_IsolateFlags* flags = nullptr); + + DartIsolate(const DartVM* vm, + fxl::RefPtr isolate_snapshot, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + std::string advisory_script_uri, + std::string advisory_script_entrypoint); + + ~DartIsolate() override; + + Phase GetPhase() const; + + FXL_WARN_UNUSED_RESULT + bool PrepareForRunningFromPrecompiledCode(); + + FXL_WARN_UNUSED_RESULT + bool PrepareForRunningFromSnapshot(std::unique_ptr snapshot); + + FXL_WARN_UNUSED_RESULT + bool PrepareForRunningFromSource(const std::string& main_source_file, + const std::string& packages); + + FXL_WARN_UNUSED_RESULT + bool Run(const std::string& entrypoint); + + FXL_WARN_UNUSED_RESULT + bool Shutdown(); + + void AddIsolateShutdownCallback(fxl::Closure closure); + + const DartVM* GetDartVM() const; + + fxl::RefPtr GetIsolateSnapshot() const; + + fml::WeakPtr GetWeakIsolatePtr() const; + + private: + class AutoFireClosure { + public: + AutoFireClosure(fxl::Closure closure) : closure_(std::move(closure)) {} + ~AutoFireClosure() { + if (closure_) { + closure_(); + } + } + + private: + fxl::Closure closure_; + FXL_DISALLOW_COPY_AND_ASSIGN(AutoFireClosure); + }; + friend class DartVM; + + const DartVM* vm_ = nullptr; + Phase phase_ = Phase::Unknown; + const fxl::RefPtr isolate_snapshot_; + std::vector> shutdown_callbacks_; + fml::WeakPtr weak_prototype_; + fml::WeakPtrFactory weak_factory_; + + FXL_WARN_UNUSED_RESULT + bool Initialize(Dart_Isolate isolate, bool is_root_isolate); + + FXL_WARN_UNUSED_RESULT + bool LoadLibraries(); + + bool UpdateThreadPoolNames() const; + + FXL_WARN_UNUSED_RESULT + bool MarkIsolateRunnable(); + + // |Dart_IsolateCreateCallback| + static Dart_Isolate DartIsolateCreateCallback( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + DartIsolate* embedder_isolate, + char** error); + + static std::pair /* embedder */> + CreateDartVMAndEmbedderObjectPair(const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + DartIsolate* parent_embedder_isolate, + bool is_root_isolate, + char** error); + + // |Dart_IsolateShutdownCallback| + static void DartIsolateShutdownCallback(DartIsolate* embedder_isolate); + + // |Dart_IsolateCleanupCallback| + static void DartIsolateCleanupCallback(DartIsolate* embedder_isolate); + + FXL_DISALLOW_COPY_AND_ASSIGN(DartIsolate); +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_ISOLATE_H_ diff --git a/runtime/dart_isolate_unittests.cc b/runtime/dart_isolate_unittests.cc new file mode 100644 index 0000000000000..d8f2e02382da1 --- /dev/null +++ b/runtime/dart_isolate_unittests.cc @@ -0,0 +1,103 @@ +// 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/thread.h" +#include "flutter/runtime/dart_isolate.h" +#include "flutter/runtime/dart_vm.h" +#include "flutter/testing/testing.h" +#include "flutter/testing/thread_test.h" + +#define CURRENT_TEST_NAME \ + std::string { \ + ::testing::UnitTest::GetInstance()->current_test_info()->name() \ + } + +namespace blink { + +using DartIsolateTest = ::testing::ThreadTest; + +TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + auto vm = DartVM::ForProcess(settings); + ASSERT_TRUE(vm); + TaskRunners task_runners(CURRENT_TEST_NAME, // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner() // + ); + auto root_isolate = DartIsolate::CreateRootIsolate( + vm.get(), // vm + vm->GetIsolateSnapshot(), // isolate snapshot + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); + ASSERT_TRUE(root_isolate); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); + ASSERT_TRUE(root_isolate->Shutdown()); +} + +TEST_F(DartIsolateTest, IsolateCanAssociateSnapshot) { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + auto vm = DartVM::ForProcess(settings); + ASSERT_TRUE(vm); + TaskRunners task_runners(CURRENT_TEST_NAME, // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner() // + ); + auto root_isolate = DartIsolate::CreateRootIsolate( + vm.get(), // vm + vm->GetIsolateSnapshot(), // isolate snapshot + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); + ASSERT_TRUE(root_isolate); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); + ASSERT_TRUE(root_isolate->PrepareForRunningFromSource( + testing::GetFixturesPath() + std::string{"/simple_main.dart"}, "")); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Ready); + ASSERT_TRUE(root_isolate->Shutdown()); +} + +TEST_F(DartIsolateTest, CanResolveAndInvokeMethod) { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + auto vm = DartVM::ForProcess(settings); + ASSERT_TRUE(vm); + TaskRunners task_runners(CURRENT_TEST_NAME, // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner(), // + GetCurrentTaskRunner() // + ); + auto root_isolate = DartIsolate::CreateRootIsolate( + vm.get(), // vm + vm->GetIsolateSnapshot(), // isolate snapshot + std::move(task_runners), // task runners + nullptr, // window + {}, // resource context + nullptr // unref qeueue + ); + ASSERT_TRUE(root_isolate); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); + ASSERT_TRUE(root_isolate->PrepareForRunningFromSource( + testing::GetFixturesPath() + std::string{"/simple_main.dart"}, "")); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Ready); + ASSERT_TRUE(root_isolate->Run("simple_main")); + ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Running); + ASSERT_TRUE(root_isolate->Shutdown()); +} + +} // namespace blink diff --git a/runtime/dart_service_isolate.h b/runtime/dart_service_isolate.h index 9edd663feb6bd..59a02e2e9d495 100644 --- a/runtime/dart_service_isolate.h +++ b/runtime/dart_service_isolate.h @@ -13,8 +13,6 @@ namespace blink { class DartServiceIsolate { public: - static bool Bootstrap(); - static bool Startup(std::string server_ip, intptr_t server_port, Dart_LibraryTagHandler embedder_tag_handler, diff --git a/runtime/dart_snapshot.cc b/runtime/dart_snapshot.cc new file mode 100644 index 0000000000000..5d759257d1d4b --- /dev/null +++ b/runtime/dart_snapshot.cc @@ -0,0 +1,159 @@ +// 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/runtime/dart_snapshot.h" + +#include + +#include "flutter/fml/native_library.h" +#include "flutter/fml/paths.h" +#include "flutter/fml/trace_event.h" +#include "flutter/runtime/dart_snapshot_buffer.h" +#include "flutter/runtime/dart_vm.h" + +namespace blink { + +const char* DartSnapshot::kVMDataSymbol = "kDartVmSnapshotData"; +const char* DartSnapshot::kVMInstructionsSymbol = "kDartVmSnapshotInstructions"; +const char* DartSnapshot::kIsolateDataSymbol = "kDartIsolateSnapshotData"; +const char* DartSnapshot::kIsolateInstructionsSymbol = + "kDartIsolateSnapshotInstructions"; + +static std::unique_ptr ResolveVMData( + const Settings& settings) { + if (settings.aot_snapshot_path.size() > 0) { + auto path = fml::paths::JoinPaths( + {settings.aot_snapshot_path, settings.aot_vm_snapshot_data_filename}); + if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( + path.c_str(), false /* executable */)) { + return source; + } + } + + auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); + return DartSnapshotBuffer::CreateWithSymbolInLibrary( + loaded_process, DartSnapshot::kVMDataSymbol); +} + +static std::unique_ptr ResolveVMInstructions( + const Settings& settings) { + if (settings.aot_snapshot_path.size() > 0) { + auto path = fml::paths::JoinPaths( + {settings.aot_snapshot_path, settings.aot_vm_snapshot_instr_filename}); + if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( + path.c_str(), true /* executable */)) { + return source; + } + } + + if (settings.application_library_path.size() > 0) { + auto library = + fml::NativeLibrary::Create(settings.application_library_path.c_str()); + if (auto source = DartSnapshotBuffer::CreateWithSymbolInLibrary( + library, DartSnapshot::kVMInstructionsSymbol)) { + return source; + } + } + + auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); + return DartSnapshotBuffer::CreateWithSymbolInLibrary( + loaded_process, DartSnapshot::kVMInstructionsSymbol); +} + +static std::unique_ptr ResolveIsolateData( + const Settings& settings) { + if (settings.aot_snapshot_path.size() > 0) { + auto path = + fml::paths::JoinPaths({settings.aot_snapshot_path, + settings.aot_isolate_snapshot_data_filename}); + if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( + path.c_str(), false /* executable */)) { + return source; + } + } + + auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); + return DartSnapshotBuffer::CreateWithSymbolInLibrary( + loaded_process, DartSnapshot::kIsolateDataSymbol); +} + +static std::unique_ptr ResolveIsolateInstructions( + const Settings& settings) { + if (settings.aot_snapshot_path.size() > 0) { + auto path = + fml::paths::JoinPaths({settings.aot_snapshot_path, + settings.aot_isolate_snapshot_instr_filename}); + if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( + path.c_str(), true /* executable */)) { + return source; + } + } + + if (settings.application_library_path.size() > 0) { + auto library = + fml::NativeLibrary::Create(settings.application_library_path.c_str()); + if (auto source = DartSnapshotBuffer::CreateWithSymbolInLibrary( + library, DartSnapshot::kIsolateInstructionsSymbol)) { + return source; + } + } + + auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); + return DartSnapshotBuffer::CreateWithSymbolInLibrary( + loaded_process, DartSnapshot::kIsolateInstructionsSymbol); +} + +fxl::RefPtr DartSnapshot::VMSnapshotFromSettings( + const Settings& settings) { + TRACE_EVENT0("flutter", "DartSnapshot::VMSnapshotFromSettings"); + auto snapshot = + fxl::MakeRefCounted(ResolveVMData(settings), // + ResolveVMInstructions(settings) // + ); + if (snapshot->IsValid()) { + return snapshot; + } + return nullptr; +} + +fxl::RefPtr DartSnapshot::IsolateSnapshotFromSettings( + const Settings& settings) { + TRACE_EVENT0("flutter", "DartSnapshot::IsolateSnapshotFromSettings"); + auto snapshot = + fxl::MakeRefCounted(ResolveIsolateData(settings), // + ResolveIsolateInstructions(settings) // + ); + if (snapshot->IsValid()) { + return snapshot; + } + return nullptr; +} + +DartSnapshot::DartSnapshot(std::unique_ptr data, + std::unique_ptr instructions) + : data_(std::move(data)), instructions_(std::move(instructions)) {} + +DartSnapshot::~DartSnapshot() = default; + +bool DartSnapshot::IsValid() const { + return static_cast(data_); +} + +bool DartSnapshot::IsValidForAOT() const { + return data_ && instructions_; +} + +const DartSnapshotBuffer* DartSnapshot::GetData() const { + return data_.get(); +} + +const DartSnapshotBuffer* DartSnapshot::GetInstructions() const { + return instructions_.get(); +} + +const uint8_t* DartSnapshot::GetInstructionsIfPresent() const { + return instructions_ ? instructions_->GetSnapshotPointer() : nullptr; +} + +} // namespace blink diff --git a/runtime/dart_snapshot.h b/runtime/dart_snapshot.h new file mode 100644 index 0000000000000..4f04765b4f5a9 --- /dev/null +++ b/runtime/dart_snapshot.h @@ -0,0 +1,57 @@ +// 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_RUNTIME_DART_SNAPSHOT_H_ +#define FLUTTER_RUNTIME_DART_SNAPSHOT_H_ + +#include +#include + +#include "flutter/common/settings.h" +#include "flutter/runtime/dart_snapshot_buffer.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/ref_counted.h" + +namespace blink { + +class DartSnapshot : public fxl::RefCountedThreadSafe { + public: + static const char* kVMDataSymbol; + static const char* kVMInstructionsSymbol; + static const char* kIsolateDataSymbol; + static const char* kIsolateInstructionsSymbol; + + static fxl::RefPtr VMSnapshotFromSettings( + const Settings& settings); + + static fxl::RefPtr IsolateSnapshotFromSettings( + const Settings& settings); + + bool IsValid() const; + + bool IsValidForAOT() const; + + const DartSnapshotBuffer* GetData() const; + + const DartSnapshotBuffer* GetInstructions() const; + + const uint8_t* GetInstructionsIfPresent() const; + + private: + std::unique_ptr data_; + std::unique_ptr instructions_; + + DartSnapshot(std::unique_ptr data, + std::unique_ptr instructions); + + ~DartSnapshot(); + + FRIEND_REF_COUNTED_THREAD_SAFE(DartSnapshot); + FRIEND_MAKE_REF_COUNTED(DartSnapshot); + FXL_DISALLOW_COPY_AND_ASSIGN(DartSnapshot); +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_SNAPSHOT_H_ diff --git a/runtime/dart_snapshot_buffer.cc b/runtime/dart_snapshot_buffer.cc new file mode 100644 index 0000000000000..c39233ac8334a --- /dev/null +++ b/runtime/dart_snapshot_buffer.cc @@ -0,0 +1,72 @@ +// 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/runtime/dart_snapshot_buffer.h" + +#include + +#include "flutter/fml/mapping.h" + +namespace blink { + +class NativeLibrarySnapshotBuffer final : public DartSnapshotBuffer { + public: + NativeLibrarySnapshotBuffer(fxl::RefPtr library, + const char* symbol_name) + : library_(std::move(library)) { + if (library_) { + symbol_ = library_->ResolveSymbol(symbol_name); + } + } + + const uint8_t* GetSnapshotPointer() const override { return symbol_; } + + size_t GetSnapshotSize() const override { return 0; } + + private: + fxl::RefPtr library_; + const uint8_t* symbol_ = nullptr; + + FXL_DISALLOW_COPY_AND_ASSIGN(NativeLibrarySnapshotBuffer); +}; + +class FileSnapshotBuffer final : public DartSnapshotBuffer { + public: + FileSnapshotBuffer(const char* path, bool executable) + : mapping_(path, executable) { + if (mapping_.GetSize() > 0) { + symbol_ = mapping_.GetMapping(); + } + } + + const uint8_t* GetSnapshotPointer() const override { return symbol_; } + + size_t GetSnapshotSize() const override { return mapping_.GetSize(); } + + private: + fml::FileMapping mapping_; + const uint8_t* symbol_ = nullptr; + + FXL_DISALLOW_COPY_AND_ASSIGN(FileSnapshotBuffer); +}; + +std::unique_ptr +DartSnapshotBuffer::CreateWithSymbolInLibrary( + fxl::RefPtr library, + const char* symbol_name) { + auto source = std::make_unique( + std::move(library), symbol_name); + return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source); +} + +std::unique_ptr +DartSnapshotBuffer::CreateWithContentsOfFile(const char* file_path, + bool executable) { + auto source = std::make_unique(file_path, executable); + return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source); +} + +DartSnapshotBuffer::~DartSnapshotBuffer() = default; + +} // namespace blink diff --git a/runtime/dart_snapshot_buffer.h b/runtime/dart_snapshot_buffer.h new file mode 100644 index 0000000000000..675946c0ca63f --- /dev/null +++ b/runtime/dart_snapshot_buffer.h @@ -0,0 +1,34 @@ +// 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_RUNTIME_DART_SNAPSHOT_BUFFER_H_ +#define FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_ + +#include + +#include "flutter/fml/native_library.h" +#include "lib/fxl/macros.h" + +namespace blink { + +class DartSnapshotBuffer { + public: + static std::unique_ptr CreateWithSymbolInLibrary( + fxl::RefPtr library, + const char* symbol_name); + + static std::unique_ptr CreateWithContentsOfFile( + const char* file_path, + bool executable); + + virtual ~DartSnapshotBuffer(); + + virtual const uint8_t* GetSnapshotPointer() const = 0; + + virtual size_t GetSnapshotSize() const = 0; +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_ diff --git a/runtime/dart_vm.cc b/runtime/dart_vm.cc new file mode 100644 index 0000000000000..bb46779078583 --- /dev/null +++ b/runtime/dart_vm.cc @@ -0,0 +1,472 @@ +// 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/runtime/dart_vm.h" + +#include + +#include +#include + +#include "flutter/common/settings.h" +#include "flutter/fml/trace_event.h" +#include "flutter/lib/io/dart_io.h" +#include "flutter/lib/ui/dart_runtime_hooks.h" +#include "flutter/lib/ui/dart_ui.h" +#include "flutter/runtime/dart_isolate.h" +#include "flutter/runtime/dart_service_isolate.h" +#include "flutter/runtime/start_up.h" +#include "lib/fxl/arraysize.h" +#include "lib/fxl/compiler_specific.h" +#include "lib/fxl/files/file.h" +#include "lib/fxl/logging.h" +#include "lib/fxl/time/time_delta.h" +#include "lib/tonic/converter/dart_converter.h" +#include "lib/tonic/dart_class_library.h" +#include "lib/tonic/dart_class_provider.h" +#include "lib/tonic/dart_sticky_error.h" +#include "lib/tonic/file_loader/file_loader.h" +#include "lib/tonic/logging/dart_error.h" +#include "lib/tonic/scopes/dart_api_scope.h" +#include "lib/tonic/typed_data/uint8_list.h" +#include "third_party/dart/runtime/bin/embedded_dart_io.h" + +#ifdef ERROR +#undef ERROR +#endif + +namespace dart { +namespace observatory { + +#if !OS(FUCHSIA) && (FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE) + +// These two symbols are defined in |observatory_archive.cc| which is generated +// by the |//third_party/dart/runtime/observatory:archive_observatory| rule. +// Both of these symbols will be part of the data segment and therefore are read +// only. +extern unsigned int observatory_assets_archive_len; +extern const uint8_t* observatory_assets_archive; + +#endif // !OS(FUCHSIA) && (FLUTTER_RUNTIME_MODE != + // FLUTTER_RUNTIME_MODE_RELEASE) + +} // namespace observatory +} // namespace dart + +namespace blink { + +// Arguments passed to the Dart VM in all configurations. +static const char* kDartLanguageArgs[] = { + "--enable_mirrors=false", "--background_compilation", "--await_is_keyword", + "--causal_async_stacks", "--limit-ints-to-64-bits", +}; + +static const char* kDartPrecompilationArgs[] = { + "--precompilation", +}; + +FXL_ALLOW_UNUSED_TYPE +static const char* kDartWriteProtectCodeArgs[] = { + "--no_write_protect_code", +}; + +static const char* kDartAssertArgs[] = { + // clang-format off + "--enable_asserts", + // clang-format on +}; + +static const char* kDartCheckedModeArgs[] = { + // clang-format off + "--enable_type_checks", + "--error_on_bad_type", + "--error_on_bad_override", + // clang-format on +}; + +static const char* kDartStrongModeArgs[] = { + // clang-format off + "--strong", + "--reify_generic_functions", + "--limit_ints_to_64_bits", + "--sync_async", + // clang-format on +}; + +static const char* kDartStartPausedArgs[]{ + "--pause_isolates_on_start", +}; + +static const char* kDartTraceStartupArgs[]{ + "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,VM", +}; + +static const char* kDartEndlessTraceBufferArgs[]{ + "--timeline_recorder=endless", +}; + +static const char* kDartFuchsiaTraceArgs[] FXL_ALLOW_UNUSED_TYPE = { + "--systrace_timeline", + "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,VM", +}; + +constexpr char kFileUriPrefix[] = "file://"; +constexpr size_t kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1; + +bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) { + if (strncmp(source_url, kFileUriPrefix, kFileUriPrefixLength) != 0u) { + // Assume modified. + return true; + } + + const char* path = source_url + kFileUriPrefixLength; + struct stat info; + if (stat(path, &info) < 0) + return true; + + // If st_mtime is zero, it's more likely that the file system doesn't support + // mtime than that the file was actually modified in the 1970s. + if (!info.st_mtime) + return true; + + // It's very unclear what time bases we're with here. The Dart API doesn't + // document the time base for since_ms. Reading the code, the value varies by + // platform, with a typical source being something like gettimeofday. + // + // We add one to st_mtime because st_mtime has less precision than since_ms + // and we want to treat the file as modified if the since time is between + // ticks of the mtime. + fxl::TimeDelta mtime = fxl::TimeDelta::FromSeconds(info.st_mtime + 1); + fxl::TimeDelta since = fxl::TimeDelta::FromMilliseconds(since_ms); + + return mtime > since; +} + +void ThreadExitCallback() {} + +Dart_Handle GetVMServiceAssetsArchiveCallback() { +#if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE) + return nullptr; +#elif OS(FUCHSIA) + std::vector observatory_assets_archive; + if (!files::ReadFileToVector("pkg/data/observatory.tar", + &observatory_assets_archive)) { + FXL_LOG(ERROR) << "Fail to load Observatory archive"; + return nullptr; + } + return tonic::DartConverter::ToDart( + observatory_assets_archive.data(), observatory_assets_archive.size()); +#else + return tonic::DartConverter::ToDart( + ::dart::observatory::observatory_assets_archive, + ::dart::observatory::observatory_assets_archive_len); +#endif +} + +static const char kStdoutStreamId[] = "Stdout"; +static const char kStderrStreamId[] = "Stderr"; + +static bool ServiceStreamListenCallback(const char* stream_id) { + if (strcmp(stream_id, kStdoutStreamId) == 0) { + dart::bin::SetCaptureStdout(true); + return true; + } else if (strcmp(stream_id, kStderrStreamId) == 0) { + dart::bin::SetCaptureStderr(true); + return true; + } + return false; +} + +static void ServiceStreamCancelCallback(const char* stream_id) { + if (strcmp(stream_id, kStdoutStreamId) == 0) { + dart::bin::SetCaptureStdout(false); + } else if (strcmp(stream_id, kStderrStreamId) == 0) { + dart::bin::SetCaptureStderr(false); + } +} + +bool DartVM::IsRunningPrecompiledCode() { + return Dart_IsPrecompiledRuntime(); +} + +static std::vector ProfilingFlags(bool enable_profiling) { +// Disable Dart's built in profiler when building a debug build. This +// works around a race condition that would sometimes stop a crash's +// stack trace from being printed on Android. +#ifndef NDEBUG + enable_profiling = false; +#endif + + // We want to disable profiling by default because it overwhelms LLDB. But + // the VM enables the same by default. In either case, we have some profiling + // flags. + if (enable_profiling) { + return {// This is the default. But just be explicit. + "--profiler", + // This instructs the profiler to walk C++ frames, and to include + // them in the profile. + "--profile-vm"}; + } else { + return {"--no-profiler"}; + } +} + +void PushBackAll(std::vector* args, + const char** argv, + size_t argc) { + for (size_t i = 0; i < argc; ++i) { + args->push_back(argv[i]); + } +} + +static void EmbedderInformationCallback(Dart_EmbedderInformation* info) { + info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION; + dart::bin::GetIOEmbedderInformation(info); + info->name = "Flutter"; +} + +fxl::RefPtr DartVM::ForProcess(Settings settings) { + return ForProcess(settings, nullptr, nullptr); +} + +static std::once_flag gVMInitialization; +static fxl::RefPtr gVM; + +fxl::RefPtr DartVM::ForProcess( + Settings settings, + fxl::RefPtr vm_snapshot, + fxl::RefPtr isolate_snapshot) { + std::call_once(gVMInitialization, [settings, // + vm_snapshot, // + isolate_snapshot // + ]() mutable { + if (!vm_snapshot) { + vm_snapshot = DartSnapshot::VMSnapshotFromSettings(settings); + } + if (!isolate_snapshot) { + isolate_snapshot = DartSnapshot::IsolateSnapshotFromSettings(settings); + } + gVM = fxl::MakeRefCounted(settings, // + std::move(vm_snapshot), // + std::move(isolate_snapshot) // + ); + }); + return gVM; +} + +fxl::RefPtr DartVM::ForProcessIfInitialized() { + return gVM; +} + +DartVM::DartVM(const Settings& settings, + fxl::RefPtr vm_snapshot, + fxl::RefPtr isolate_snapshot) + : settings_(settings), + vm_snapshot_(std::move(vm_snapshot)), + isolate_snapshot_(std::move(isolate_snapshot)), + platform_kernel_mapping_( + std::make_unique(settings.kernel_snapshot_path)), + weak_factory_(this) { + TRACE_EVENT0("flutter", "DartVMInitializer"); + FXL_DLOG(INFO) << "Attempting Dart VM launch for mode: " + << (IsRunningPrecompiledCode() ? "AOT" : "Interpreter"); + + FXL_DCHECK(vm_snapshot_ && vm_snapshot_->IsValid()) + << "VM snapshot must be valid."; + + FXL_DCHECK(isolate_snapshot_ && isolate_snapshot_->IsValid()) + << "Isolate snapshot must be valid."; + + if (platform_kernel_mapping_->GetSize() > 0) { + // The platform kernel mapping lifetime is managed by this instance of the + // DartVM and hence will exceed that of the PlatformKernel. So provide an + // empty release callback. + Dart_ReleaseBufferCallback empty = [](auto arg) {}; + platform_kernel_ = reinterpret_cast(Dart_ReadKernelBinary( + platform_kernel_mapping_->GetMapping(), // buffer + platform_kernel_mapping_->GetSize(), // buffer size + empty // buffer deleter + )); + } + + { + TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo"); + dart::bin::BootstrapDartIo(); + + if (!settings.temp_directory_path.empty()) { + dart::bin::SetSystemTempDirectory(settings.temp_directory_path.c_str()); + } + } + + std::vector args; + + // Instruct the VM to ignore unrecognized flags. + // There is a lot of diversity in a lot of combinations when it + // comes to the arguments the VM supports. And, if the VM comes across a flag + // it does not recognize, it exits immediately. + args.push_back("--ignore-unrecognized-flags"); + + for (const auto& profiler_flag : + ProfilingFlags(settings.enable_dart_profiling)) { + args.push_back(profiler_flag); + } + + PushBackAll(&args, kDartLanguageArgs, arraysize(kDartLanguageArgs)); + + if (IsRunningPrecompiledCode()) { + PushBackAll(&args, kDartPrecompilationArgs, + arraysize(kDartPrecompilationArgs)); + } + + // Enable checked mode if we are not running precompiled code. We run non- + // precompiled code only in the debug product mode. + bool use_checked_mode = !settings.dart_non_checked_mode; + +#if !OS(FUCHSIA) + if (IsRunningPrecompiledCode()) { + use_checked_mode = false; + } +#endif // !OS(FUCHSIA) + +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG + // Debug mode uses the JIT, disable code page write protection to avoid + // memory page protection changes before and after every compilation. + PushBackAll(&args, kDartWriteProtectCodeArgs, + arraysize(kDartWriteProtectCodeArgs)); +#endif + + const bool isolate_snapshot_is_dart_2 = + Dart_IsDart2Snapshot(isolate_snapshot_->GetData()->GetSnapshotPointer()); + + const bool is_preview_dart2 = + platform_kernel_ != nullptr || isolate_snapshot_is_dart_2; + + if (is_preview_dart2) { + FXL_DLOG(INFO) << "Dart 2 is enabled."; + } else { + FXL_DLOG(INFO) << "Dart 2 is NOT enabled. Platform kernel: " + << static_cast(platform_kernel_) + << " Isolate Snapshot is Dart 2: " + << isolate_snapshot_is_dart_2; + } + if (is_preview_dart2) { + PushBackAll(&args, kDartStrongModeArgs, arraysize(kDartStrongModeArgs)); + if (use_checked_mode) { + PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); + } + } else if (use_checked_mode) { + FXL_DLOG(INFO) << "Checked mode is ON"; + PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); + PushBackAll(&args, kDartCheckedModeArgs, arraysize(kDartCheckedModeArgs)); + } else { + FXL_DLOG(INFO) << "Is not Dart 2 and Checked mode is OFF"; + } + + if (settings.start_paused) { + PushBackAll(&args, kDartStartPausedArgs, arraysize(kDartStartPausedArgs)); + } + + if (settings.endless_trace_buffer || settings.trace_startup) { + // If we are tracing startup, make sure the trace buffer is endless so we + // don't lose early traces. + PushBackAll(&args, kDartEndlessTraceBufferArgs, + arraysize(kDartEndlessTraceBufferArgs)); + } + + if (settings.trace_startup) { + PushBackAll(&args, kDartTraceStartupArgs, arraysize(kDartTraceStartupArgs)); + } + +#if defined(OS_FUCHSIA) + PushBackAll(&args, kDartFuchsiaTraceArgs, arraysize(kDartFuchsiaTraceArgs)); +#endif + + for (size_t i = 0; i < settings.dart_flags.size(); i++) + args.push_back(settings.dart_flags[i].c_str()); + + FXL_CHECK(Dart_SetVMFlags(args.size(), args.data())); + + DartUI::InitForGlobal(); + + { + TRACE_EVENT0("flutter", "Dart_Initialize"); + Dart_InitializeParams params = {}; + params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; + params.vm_snapshot_data = vm_snapshot_->GetData()->GetSnapshotPointer(); + params.vm_snapshot_instructions = vm_snapshot_->GetInstructionsIfPresent(); + params.create = reinterpret_cast( + DartIsolate::DartIsolateCreateCallback); + params.shutdown = reinterpret_cast( + DartIsolate::DartIsolateShutdownCallback); + params.cleanup = reinterpret_cast( + DartIsolate::DartIsolateCleanupCallback); + params.thread_exit = ThreadExitCallback; + params.get_service_assets = GetVMServiceAssetsArchiveCallback; + params.entropy_source = DartIO::EntropySource; + char* init_error = Dart_Initialize(¶ms); + if (init_error) { + FXL_LOG(FATAL) << "Error while initializing the Dart VM: " << init_error; + ::free(init_error); + } + // Send the earliest available timestamp in the application lifecycle to + // timeline. The difference between this timestamp and the time we render + // the very first frame gives us a good idea about Flutter's startup time. + // Use a duration event so about:tracing will consider this event when + // deciding the earliest event to use as time 0. + if (blink::engine_main_enter_ts != 0) { + Dart_TimelineEvent("FlutterEngineMainEnter", // label + blink::engine_main_enter_ts, // timestamp0 + blink::engine_main_enter_ts, // timestamp1_or_async_id + Dart_Timeline_Event_Duration, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values + ); + } + } + + // Allow streaming of stdout and stderr by the Dart vm. + Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback, + &ServiceStreamCancelCallback); + + Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback); +} + +DartVM::~DartVM() { + if (Dart_CurrentIsolate() != nullptr) { + Dart_ExitIsolate(); + } + char* result = Dart_Cleanup(); + if (result != nullptr) { + FXL_LOG(ERROR) << "Could not cleanly shut down the Dart VM. Message: \"" + << result << "\"."; + free(result); + } +} + +const Settings& DartVM::GetSettings() const { + return settings_; +} + +DartVM::PlatformKernel* DartVM::GetPlatformKernel() const { + return platform_kernel_; +} + +const DartSnapshot& DartVM::GetVMSnapshot() const { + return *vm_snapshot_.get(); +} + +fxl::RefPtr DartVM::GetIsolateSnapshot() const { + return isolate_snapshot_; +} + +ServiceProtocol& DartVM::GetServiceProtocol() { + return service_protocol_; +} + +fxl::WeakPtr DartVM::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +} // namespace blink diff --git a/runtime/dart_vm.h b/runtime/dart_vm.h new file mode 100644 index 0000000000000..e8feb9ba1de92 --- /dev/null +++ b/runtime/dart_vm.h @@ -0,0 +1,75 @@ +// 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_RUNTIME_DART_VM_H_ +#define FLUTTER_RUNTIME_DART_VM_H_ + +#include +#include +#include + +#include "flutter/common/settings.h" +#include "flutter/runtime/dart_isolate.h" +#include "flutter/runtime/dart_snapshot.h" +#include "flutter/runtime/service_protocol.h" +#include "lib/fxl/build_config.h" +#include "lib/fxl/functional/closure.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/ref_counted.h" +#include "lib/fxl/memory/ref_ptr.h" +#include "lib/fxl/memory/weak_ptr.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace blink { + +class DartVM : public fxl::RefCountedThreadSafe { + public: + class PlatformKernel; + + static fxl::RefPtr ForProcess(Settings settings); + + static fxl::RefPtr ForProcess( + Settings settings, + fxl::RefPtr vm_snapshot, + fxl::RefPtr isolate_snapshot); + + static fxl::RefPtr ForProcessIfInitialized(); + + static bool IsRunningPrecompiledCode(); + + const Settings& GetSettings() const; + + PlatformKernel* GetPlatformKernel() const; + + const DartSnapshot& GetVMSnapshot() const; + + fxl::RefPtr GetIsolateSnapshot() const; + + fxl::WeakPtr GetWeakPtr(); + + ServiceProtocol& GetServiceProtocol(); + + private: + const Settings settings_; + const fxl::RefPtr vm_snapshot_; + const fxl::RefPtr isolate_snapshot_; + std::unique_ptr platform_kernel_mapping_; + PlatformKernel* platform_kernel_ = nullptr; + ServiceProtocol service_protocol_; + fxl::WeakPtrFactory weak_factory_; + + DartVM(const Settings& settings, + fxl::RefPtr vm_snapshot, + fxl::RefPtr isolate_snapshot); + + ~DartVM(); + + FRIEND_REF_COUNTED_THREAD_SAFE(DartVM); + FRIEND_MAKE_REF_COUNTED(DartVM); + FXL_DISALLOW_COPY_AND_ASSIGN(DartVM); +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_VM_H_ diff --git a/runtime/dart_vm_unittests.cc b/runtime/dart_vm_unittests.cc new file mode 100644 index 0000000000000..5b2f5e6ee8299 --- /dev/null +++ b/runtime/dart_vm_unittests.cc @@ -0,0 +1,21 @@ +// 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/runtime/dart_vm.h" +#include "gtest/gtest.h" + +namespace blink { + +TEST(DartVM, SimpleInitialization) { + Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + auto vm = DartVM::ForProcess(settings); + ASSERT_TRUE(vm); + ASSERT_EQ(vm, DartVM::ForProcess(settings)); + ASSERT_FALSE(DartVM::IsRunningPrecompiledCode()); + ASSERT_EQ(vm->GetPlatformKernel(), nullptr); +} + +} // namespace blink diff --git a/runtime/fixtures/simple_main.dart b/runtime/fixtures/simple_main.dart new file mode 100644 index 0000000000000..552dfbe344902 --- /dev/null +++ b/runtime/fixtures/simple_main.dart @@ -0,0 +1,7 @@ +// Copyright 2016 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. + +void simple_main() { + print("Hello"); +} diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 75796cd68697e..d3e138c937f60 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -4,192 +4,244 @@ #include "flutter/runtime/runtime_controller.h" +#include "flutter/fml/message_loop.h" #include "flutter/glue/trace_event.h" #include "flutter/lib/ui/compositing/scene.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/window.h" -#include "flutter/runtime/dart_controller.h" #include "flutter/runtime/runtime_delegate.h" #include "lib/tonic/dart_message_handler.h" -using tonic::DartState; - namespace blink { -std::unique_ptr RuntimeController::Create( - RuntimeDelegate* client) { - return std::unique_ptr(new RuntimeController(client)); +RuntimeController::RuntimeController( + RuntimeDelegate& p_client, + const DartVM* p_vm, + TaskRunners p_task_runners, + fml::WeakPtr p_resource_context, + fxl::RefPtr p_unref_queue) + : RuntimeController(p_client, + p_vm, + std::move(p_task_runners), + std::move(p_resource_context), + std::move(p_unref_queue), + WindowData{/* default window data */}) {} + +RuntimeController::RuntimeController( + RuntimeDelegate& p_client, + const DartVM* p_vm, + TaskRunners p_task_runners, + fml::WeakPtr p_resource_context, + fxl::RefPtr p_unref_queue, + WindowData p_window_data) + : client_(p_client), + vm_(p_vm), + task_runners_(p_task_runners), + resource_context_(p_resource_context), + unref_queue_(p_unref_queue), + window_data_(std::move(p_window_data)), + root_isolate_( + DartIsolate::CreateRootIsolate(vm_, + vm_->GetIsolateSnapshot(), + task_runners_, + std::make_unique(this), + resource_context_, + unref_queue_)) { + root_isolate_->SetReturnCodeCallback([this](uint32_t code) { + root_isolate_return_code_ = {true, code}; + }); + if (auto window = GetWindowIfAvailable()) { + tonic::DartState::Scope scope(root_isolate_.get()); + window->DidCreateIsolate(); + if (!FlushRuntimeStateToIsolate()) { + FXL_DLOG(ERROR) << "Could not setup intial isolate state."; + } + } else { + FXL_DCHECK(false) << "RuntimeController created without window binding."; + } + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); +} + +RuntimeController::~RuntimeController() { + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); + if (root_isolate_) { + root_isolate_->SetReturnCodeCallback(nullptr); + auto result = root_isolate_->Shutdown(); + if (!result) { + FXL_DLOG(ERROR) << "Could not shutdown the root isolate."; + } + root_isolate_ = {}; + } } -RuntimeController::RuntimeController(RuntimeDelegate* client) - : client_(client) {} - -RuntimeController::~RuntimeController() {} +std::unique_ptr RuntimeController::Clone() const { + return std::unique_ptr(new RuntimeController( + client_, // + vm_, // + task_runners_, // + resource_context_, // + unref_queue_, // + window_data_ // + )); +} -void RuntimeController::CreateDartController( - const std::string& script_uri, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instr, - int dirfd) { - FXL_DCHECK(!dart_controller_); +bool RuntimeController::FlushRuntimeStateToIsolate() { + return SetViewportMetrics(window_data_.viewport_metrics) && + SetLocale(window_data_.language_code, window_data_.country_code) && + SetSemanticsEnabled(window_data_.semantics_enabled); +} - dart_controller_.reset(new DartController()); - dart_controller_->CreateIsolateFor( - script_uri, isolate_snapshot_data, isolate_snapshot_instr, - std::make_unique(this, std::make_unique(this), - dirfd)); +bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { + window_data_.viewport_metrics = metrics; - UIDartState* dart_state = dart_controller_->dart_state(); - DartState::Scope scope(dart_state); - dart_state->window()->DidCreateIsolate(); - client_->DidCreateMainIsolate(dart_state->isolate()); + if (auto window = GetWindowIfAvailable()) { + window->UpdateWindowMetrics(metrics); + return true; + } + return false; +} - Window* window = GetWindow(); +bool RuntimeController::SetLocale(const std::string& language_code, + const std::string& country_code) { + window_data_.language_code = language_code; + window_data_.country_code = country_code; - window->UpdateLocale(language_code_, country_code_); + if (auto window = GetWindowIfAvailable()) { + window->UpdateLocale(window_data_.language_code, window_data_.country_code); + return true; + } - if (semantics_enabled_) - window->UpdateSemanticsEnabled(semantics_enabled_); + return false; } -void RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { - GetWindow()->UpdateWindowMetrics(metrics); -} +bool RuntimeController::SetUserSettingsData(const std::string& data) { + window_data_.user_settings_data = data; -void RuntimeController::SetLocale(const std::string& language_code, - const std::string& country_code) { - if (language_code_ == language_code && country_code_ == country_code) - return; + if (auto window = GetWindowIfAvailable()) { + window->UpdateUserSettingsData(window_data_.user_settings_data); + return true; + } - language_code_ = language_code; - country_code_ = country_code; - GetWindow()->UpdateLocale(language_code_, country_code_); + return false; } -void RuntimeController::SetUserSettingsData(const std::string& data) { - if (user_settings_data_ == data) - return; - user_settings_data_ = data; - GetWindow()->UpdateUserSettingsData(user_settings_data_); -} +bool RuntimeController::SetSemanticsEnabled(bool enabled) { + window_data_.semantics_enabled = enabled; + + if (auto window = GetWindowIfAvailable()) { + window->UpdateSemanticsEnabled(window_data_.semantics_enabled); + return true; + } -void RuntimeController::SetSemanticsEnabled(bool enabled) { - if (semantics_enabled_ == enabled) - return; - semantics_enabled_ = enabled; - GetWindow()->UpdateSemanticsEnabled(semantics_enabled_); + return false; } -void RuntimeController::BeginFrame(fxl::TimePoint frame_time) { - GetWindow()->BeginFrame(frame_time); +bool RuntimeController::BeginFrame(fxl::TimePoint frame_time) { + if (auto window = GetWindowIfAvailable()) { + window->BeginFrame(frame_time); + return true; + } + return false; } -void RuntimeController::NotifyIdle(int64_t deadline) { - UIDartState* dart_state = dart_controller_->dart_state(); - if (!dart_state) { - return; +bool RuntimeController::NotifyIdle(int64_t deadline) { + if (!root_isolate_) { + return false; } - DartState::Scope scope(dart_state); + + tonic::DartState::Scope scope(root_isolate_.get()); Dart_NotifyIdle(deadline); + return true; } -void RuntimeController::DispatchPlatformMessage( +bool RuntimeController::DispatchPlatformMessage( fxl::RefPtr message) { - TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", "mode", - "basic"); - GetWindow()->DispatchPlatformMessage(std::move(message)); + if (auto window = GetWindowIfAvailable()) { + TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", + "mode", "basic"); + window->DispatchPlatformMessage(std::move(message)); + return true; + } + return false; } -void RuntimeController::DispatchPointerDataPacket( +bool RuntimeController::DispatchPointerDataPacket( const PointerDataPacket& packet) { - TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", - "mode", "basic"); - GetWindow()->DispatchPointerDataPacket(packet); + if (auto window = GetWindowIfAvailable()) { + TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", + "mode", "basic"); + window->DispatchPointerDataPacket(packet); + return true; + } + return false; } -void RuntimeController::DispatchSemanticsAction(int32_t id, +bool RuntimeController::DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector args) { TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode", "basic"); - GetWindow()->DispatchSemanticsAction(id, action, std::move(args)); + if (auto window = GetWindowIfAvailable()) { + window->DispatchSemanticsAction(id, action, std::move(args)); + return true; + } + return false; } -Window* RuntimeController::GetWindow() { - return dart_controller_->dart_state()->window(); +Window* RuntimeController::GetWindowIfAvailable() { + return root_isolate_ ? root_isolate_->window() : nullptr; } std::string RuntimeController::DefaultRouteName() { - return client_->DefaultRouteName(); + return client_.DefaultRouteName(); } void RuntimeController::ScheduleFrame() { - client_->ScheduleFrame(); + client_.ScheduleFrame(); } void RuntimeController::Render(Scene* scene) { - client_->Render(scene->takeLayerTree()); + client_.Render(scene->takeLayerTree()); } void RuntimeController::UpdateSemantics(SemanticsUpdate* update) { - if (semantics_enabled_) - client_->UpdateSemantics(update->takeNodes()); + if (window_data_.semantics_enabled) { + client_.UpdateSemantics(update->takeNodes()); + } } void RuntimeController::HandlePlatformMessage( fxl::RefPtr message) { - client_->HandlePlatformMessage(std::move(message)); -} - -void RuntimeController::DidCreateSecondaryIsolate(Dart_Isolate isolate) { - client_->DidCreateSecondaryIsolate(isolate); -} - -void RuntimeController::DidShutdownMainIsolate() { - client_->DidShutdownMainIsolate(); + client_.HandlePlatformMessage(std::move(message)); } Dart_Port RuntimeController::GetMainPort() { - if (!dart_controller_) { - return ILLEGAL_PORT; - } - if (!dart_controller_->dart_state()) { - return ILLEGAL_PORT; - } - return dart_controller_->dart_state()->main_port(); + return root_isolate_ ? root_isolate_->main_port() : ILLEGAL_PORT; } std::string RuntimeController::GetIsolateName() { - if (!dart_controller_) { - return ""; - } - if (!dart_controller_->dart_state()) { - return ""; - } - return dart_controller_->dart_state()->debug_name(); + return root_isolate_ ? root_isolate_->debug_name() : ""; } bool RuntimeController::HasLivePorts() { - if (!dart_controller_) { + if (!root_isolate_) { return false; } - UIDartState* dart_state = dart_controller_->dart_state(); - if (!dart_state) { - return false; - } - DartState::Scope scope(dart_state); + tonic::DartState::Scope scope(root_isolate_.get()); return Dart_HasLivePorts(); } tonic::DartErrorHandleType RuntimeController::GetLastError() { - if (!dart_controller_) { - return tonic::kNoError; - } - UIDartState* dart_state = dart_controller_->dart_state(); - if (!dart_state) { - return tonic::kNoError; - } - return dart_state->message_handler().isolate_last_error(); + return root_isolate_ ? root_isolate_->message_handler().isolate_last_error() + : tonic::kNoError; +} + +fml::WeakPtr RuntimeController::GetRootIsolate() { + return root_isolate_; +} + +std::pair RuntimeController::GetRootIsolateReturnCode() { + return root_isolate_return_code_; } } // namespace blink diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 628bc699395c0..326c517f31db2 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -7,71 +7,108 @@ #include +#include "flutter/common/task_runners.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/pointer_data_packet.h" #include "flutter/lib/ui/window/window.h" +#include "flutter/runtime/dart_vm.h" #include "lib/fxl/macros.h" namespace blink { -class DartController; -class DartLibraryProvider; class Scene; class RuntimeDelegate; class View; class Window; -class RuntimeController : public WindowClient, public IsolateClient { +class RuntimeController final : public WindowClient { public: - static std::unique_ptr Create(RuntimeDelegate* client); + RuntimeController(RuntimeDelegate& client, + const DartVM* vm, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue); + ~RuntimeController(); - void CreateDartController(const std::string& script_uri, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instr, - int dirfd = -1); - DartController* dart_controller() const { return dart_controller_.get(); } + std::unique_ptr Clone() const; + + bool SetViewportMetrics(const ViewportMetrics& metrics); - void SetViewportMetrics(const ViewportMetrics& metrics); - void SetLocale(const std::string& language_code, + bool SetLocale(const std::string& language_code, const std::string& country_code); - void SetUserSettingsData(const std::string& data); - void SetSemanticsEnabled(bool enabled); - void BeginFrame(fxl::TimePoint frame_time); - void NotifyIdle(int64_t deadline); + bool SetUserSettingsData(const std::string& data); + + bool SetSemanticsEnabled(bool enabled); + + bool BeginFrame(fxl::TimePoint frame_time); + + bool NotifyIdle(int64_t deadline); - void DispatchPlatformMessage(fxl::RefPtr message); - void DispatchPointerDataPacket(const PointerDataPacket& packet); - void DispatchSemanticsAction(int32_t id, + bool DispatchPlatformMessage(fxl::RefPtr message); + + bool DispatchPointerDataPacket(const PointerDataPacket& packet); + + bool DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector args); Dart_Port GetMainPort(); + std::string GetIsolateName(); + bool HasLivePorts(); + tonic::DartErrorHandleType GetLastError(); - private: - explicit RuntimeController(RuntimeDelegate* client); + fml::WeakPtr GetRootIsolate(); - Window* GetWindow(); + std::pair GetRootIsolateReturnCode(); + private: + struct WindowData { + ViewportMetrics viewport_metrics; + std::string language_code; + std::string country_code; + std::string user_settings_data = "{}"; + bool semantics_enabled = false; + }; + + RuntimeDelegate& client_; + const DartVM* vm_; + TaskRunners task_runners_; + fml::WeakPtr resource_context_; + fxl::RefPtr unref_queue_; + WindowData window_data_; + fml::WeakPtr root_isolate_; + std::pair root_isolate_return_code_ = {false, 0}; + + RuntimeController(RuntimeDelegate& client, + const DartVM* vm, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue, + WindowData data); + + Window* GetWindowIfAvailable(); + + bool FlushRuntimeStateToIsolate(); + + // |blink::WindowClient| std::string DefaultRouteName() override; + + // |blink::WindowClient| void ScheduleFrame() override; + + // |blink::WindowClient| void Render(Scene* scene) override; - void UpdateSemantics(SemanticsUpdate* update) override; - void HandlePlatformMessage(fxl::RefPtr message) override; - void DidCreateSecondaryIsolate(Dart_Isolate isolate) override; - void DidShutdownMainIsolate() override; + // |blink::WindowClient| + void UpdateSemantics(SemanticsUpdate* update) override; - RuntimeDelegate* client_; - std::string language_code_; - std::string country_code_; - std::string user_settings_data_ = "{}"; - bool semantics_enabled_ = false; - std::unique_ptr dart_controller_; + // |blink::WindowClient| + void HandlePlatformMessage(fxl::RefPtr message) override; FXL_DISALLOW_COPY_AND_ASSIGN(RuntimeController); }; diff --git a/runtime/runtime_delegate.cc b/runtime/runtime_delegate.cc index 6ec55c4c2e6a0..902672be06d8f 100644 --- a/runtime/runtime_delegate.cc +++ b/runtime/runtime_delegate.cc @@ -6,12 +6,6 @@ namespace blink { -RuntimeDelegate::~RuntimeDelegate() {} - -void RuntimeDelegate::DidCreateMainIsolate(Dart_Isolate isolate) {} - -void RuntimeDelegate::DidCreateSecondaryIsolate(Dart_Isolate isolate) {} - -void RuntimeDelegate::DidShutdownMainIsolate() {} +RuntimeDelegate::~RuntimeDelegate() = default; } // namespace blink diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index 36650fe7fb70b..c6d6c0a92b2b4 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -18,14 +18,14 @@ namespace blink { class RuntimeDelegate { public: virtual std::string DefaultRouteName() = 0; + virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0; + virtual void Render(std::unique_ptr layer_tree) = 0; + virtual void UpdateSemantics(blink::SemanticsNodeUpdates update) = 0; - virtual void HandlePlatformMessage(fxl::RefPtr message) = 0; - virtual void DidCreateMainIsolate(Dart_Isolate isolate); - virtual void DidCreateSecondaryIsolate(Dart_Isolate isolate); - virtual void DidShutdownMainIsolate(); + virtual void HandlePlatformMessage(fxl::RefPtr message) = 0; protected: virtual ~RuntimeDelegate(); diff --git a/runtime/runtime_init.cc b/runtime/runtime_init.cc deleted file mode 100644 index eda66e5495aed..0000000000000 --- a/runtime/runtime_init.cc +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/runtime/runtime_init.h" - -#include "flutter/glue/trace_event.h" -#include "flutter/runtime/dart_init.h" -#include "flutter/runtime/platform_impl.h" -#include "flutter/sky/engine/public/web/Sky.h" -#include "lib/fxl/logging.h" - -namespace blink { -namespace { - -PlatformImpl* g_platform_impl = nullptr; - -} // namespace - -void InitRuntime(const uint8_t* vm_snapshot_data, - const uint8_t* vm_snapshot_instructions, - const uint8_t* default_isolate_snapshot_data, - const uint8_t* default_isolate_snapshot_instructions, - const std::string& bundle_path) { - TRACE_EVENT0("flutter", "InitRuntime"); - - FXL_CHECK(!g_platform_impl); - g_platform_impl = new PlatformImpl(); - InitEngine(g_platform_impl); - InitDartVM(vm_snapshot_data, vm_snapshot_instructions, - default_isolate_snapshot_data, - default_isolate_snapshot_instructions, bundle_path); -} - -} // namespace blink diff --git a/runtime/runtime_init.h b/runtime/runtime_init.h deleted file mode 100644 index 515ae284e3460..0000000000000 --- a/runtime/runtime_init.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 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_RUNTIME_RUNTIME_INIT_H_ -#define FLUTTER_RUNTIME_RUNTIME_INIT_H_ - -#include -#include - -namespace blink { - -void InitRuntime(const uint8_t* vm_snapshot_data, - const uint8_t* vm_snapshot_instructions, - const uint8_t* default_isolate_snapshot_data, - const uint8_t* default_isolate_snapshot_instructions, - const std::string& bundle_path); - -} // namespace blink - -#endif // FLUTTER_RUNTIME_RUNTIME_INIT_H_ diff --git a/runtime/service_protocol.cc b/runtime/service_protocol.cc new file mode 100644 index 0000000000000..030901e54269d --- /dev/null +++ b/runtime/service_protocol.cc @@ -0,0 +1,279 @@ +// 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. + +#define RAPIDJSON_HAS_STDSTRING 1 + +#include "flutter/runtime/service_protocol.h" + +#include + +#include +#include +#include +#include + +#include "lib/fxl/synchronization/waitable_event.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +namespace blink { + +const fxl::StringView ServiceProtocol::kScreenshotExtensionName = + "_flutter.screenshot"; +const fxl::StringView ServiceProtocol::kScreenshotSkpExtensionName = + "_flutter.screenshotSkp"; +const fxl::StringView ServiceProtocol::kRunInViewExtensionName = + "_flutter.runInView"; +const fxl::StringView ServiceProtocol::kFlushUIThreadTasksExtensionName = + "_flutter.flushUIThreadTasks"; +const fxl::StringView ServiceProtocol::kSetAssetBundlePathExtensionName = + "_flutter.setAssetBundlePath"; + +static constexpr fxl::StringView kViewIdPrefx = "_flutterView/"; +static constexpr fxl::StringView kListViewsExtensionName = "_flutter.listViews"; + +ServiceProtocol::ServiceProtocol() + : endpoints_({ + // Private + kListViewsExtensionName, + + // Public + kScreenshotExtensionName, + kScreenshotSkpExtensionName, + kRunInViewExtensionName, + kFlushUIThreadTasksExtensionName, + kSetAssetBundlePathExtensionName, + }) {} + +ServiceProtocol::~ServiceProtocol() { + ToggleHooks(false); +} + +void ServiceProtocol::AddHandler(Handler* handler) { + std::lock_guard lock(handlers_mutex_); + handlers_.emplace(handler); +} + +void ServiceProtocol::RemoveHandler(Handler* handler) { + std::lock_guard lock(handlers_mutex_); + handlers_.erase(handler); +} + +void ServiceProtocol::ToggleHooks(bool set) { + for (const auto& endpoint : endpoints_) { + Dart_RegisterRootServiceRequestCallback( + endpoint.data(), // method + &ServiceProtocol::HandleMessage, // callback + set ? this : nullptr // user data + ); + } +} + +static void WriteServerErrorResponse(rapidjson::Document& document, + const char* message) { + document.SetObject(); + document.AddMember("code", -32000, document.GetAllocator()); + rapidjson::Value message_value; + message_value.SetString(message, document.GetAllocator()); + document.AddMember("message", message_value, document.GetAllocator()); +} + +bool ServiceProtocol::HandleMessage(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + Handler::ServiceProtocolMap params; + for (intptr_t i = 0; i < num_params; i++) { + params[fxl::StringView{param_keys[i]}] = fxl::StringView{param_values[i]}; + } + +#ifndef NDEBUG + FXL_DLOG(INFO) << "Service protcol method: " << method; + FXL_DLOG(INFO) << "Arguments: " << params.size(); + for (intptr_t i = 0; i < num_params; i++) { + FXL_DLOG(INFO) << " " << i + 1 << ": " << param_keys[i] << " = " + << param_values[i]; + } +#endif // NDEBUG + + rapidjson::Document document; + bool result = HandleMessage(fxl::StringView{method}, // + params, // + static_cast(user_data), // + document // + ); + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + *json_object = strdup(buffer.GetString()); + +#ifndef NDEBUG + FXL_DLOG(INFO) << "Response: " << *json_object; + FXL_DLOG(INFO) << "RPC Result: " << result; +#endif // NDEBUG + + return result; +} + +bool ServiceProtocol::HandleMessage(fxl::StringView method, + const Handler::ServiceProtocolMap& params, + ServiceProtocol* service_protocol, + rapidjson::Document& response) { + if (service_protocol == nullptr) { + WriteServerErrorResponse(response, "Service protocol unavailable."); + return false; + } + + return service_protocol->HandleMessage(method, params, response); +} + +FXL_WARN_UNUSED_RESULT +static bool HandleMessageOnHandler( + ServiceProtocol::Handler* handler, + fxl::StringView method, + const ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& document) { + FXL_DCHECK(handler); + fxl::AutoResetWaitableEvent latch; + bool result = false; + fml::TaskRunner::RunNowOrPostTask( + handler->GetServiceProtocolHandlerTaskRunner(method), + [&latch, // + &result, // + &handler, // + &method, // + ¶ms, // + &document // + ]() { + result = + handler->HandleServiceProtocolMessage(method, params, document); + latch.Signal(); + }); + latch.Wait(); + return result; +} + +bool ServiceProtocol::HandleMessage(fxl::StringView method, + const Handler::ServiceProtocolMap& params, + rapidjson::Document& response) const { + if (method == kListViewsExtensionName) { + // So far, this is the only built-in method that does not forward to the + // dynamic set of handlers. + return HandleListViewsMethod(response); + } + + std::lock_guard lock(handlers_mutex_); + + if (handlers_.size() == 0) { + WriteServerErrorResponse(response, + "There are no running service protocol handlers."); + return false; + } + + // Find the handler by its "viewId" in the params. + auto view_id_param_found = params.find(fxl::StringView{"viewId"}); + if (view_id_param_found != params.end()) { + auto handler = reinterpret_cast(std::stoull( + view_id_param_found->second.data() + kViewIdPrefx.size(), nullptr, 16)); + auto handler_found = handlers_.find(handler); + if (handler_found != handlers_.end()) { + return HandleMessageOnHandler(handler, method, params, response); + } + } + + // Handle legacy calls that do not specify a handler in their args. + // TODO(chinmaygarde): Deprecate these calls in the tools and remove these + // fallbacks. + if (method == kScreenshotExtensionName || + method == kScreenshotSkpExtensionName) { + return HandleMessageOnHandler(*handlers_.begin(), method, params, response); + } + + WriteServerErrorResponse( + response, + "Service protocol could not handle or find a handler for the " + "requested method."); + return false; +} + +static std::string CreateFlutterViewID(intptr_t handler) { + std::stringstream stream; + stream << kViewIdPrefx << "0x" << std::hex << handler; + return stream.str(); +} + +static std::string CreateIsolateID(int64_t isolate) { + std::stringstream stream; + stream << "isolates/" << isolate; + return stream.str(); +} + +void ServiceProtocol::Handler::Description::Write( + Handler* handler, + rapidjson::Value& view, + rapidjson::MemoryPoolAllocator<>& allocator) const { + view.SetObject(); + view.AddMember("type", "FlutterView", allocator); + view.AddMember("id", CreateFlutterViewID(reinterpret_cast(handler)), + allocator); + if (isolate_port != 0) { + rapidjson::Value isolate(rapidjson::Type::kObjectType); + { + isolate.AddMember("type", "@Isolate", allocator); + isolate.AddMember("fixedId", true, allocator); + isolate.AddMember("id", CreateIsolateID(isolate_port), allocator); + isolate.AddMember("name", isolate_name, allocator); + isolate.AddMember("number", isolate_port, allocator); + } + view.AddMember("isolate", isolate, allocator); + } +} + +bool ServiceProtocol::HandleListViewsMethod( + rapidjson::Document& response) const { + // Collect handler descriptions on their respective task runners. + std::lock_guard lock(handlers_mutex_); + std::vector> descriptions; + for (const auto& handler : handlers_) { + fxl::AutoResetWaitableEvent latch; + Handler::Description description; + + fml::TaskRunner::RunNowOrPostTask( + handler->GetServiceProtocolHandlerTaskRunner( + kListViewsExtensionName), // task runner + [&latch, // + &description, // + &handler // + ]() { + description = handler->GetServiceProtocolDescription(); + latch.Signal(); + }); + latch.Wait(); + descriptions.emplace_back(std::make_pair( + reinterpret_cast(handler), std::move(description))); + } + + auto& allocator = response.GetAllocator(); + + // Construct the response objects. + response.SetObject(); + response.AddMember("type", "FlutterViewList", allocator); + + rapidjson::Value viewsList(rapidjson::Type::kArrayType); + for (const auto& description : descriptions) { + rapidjson::Value view(rapidjson::Type::kObjectType); + description.second.Write(reinterpret_cast(description.first), + view, allocator); + viewsList.PushBack(view, allocator); + } + + response.AddMember("views", viewsList, allocator); + + return true; +} + +} // namespace blink diff --git a/runtime/service_protocol.h b/runtime/service_protocol.h new file mode 100644 index 0000000000000..056f7389ea79a --- /dev/null +++ b/runtime/service_protocol.h @@ -0,0 +1,99 @@ +// 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_RUNTIME_SERVICE_PROTOCOL_H_ +#define FLUTTER_RUNTIME_SERVICE_PROTOCOL_H_ + +#include +#include +#include +#include + +#include "flutter/fml/task_runner.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/strings/string_view.h" +#include "lib/fxl/synchronization/thread_annotations.h" +#include "third_party/rapidjson/rapidjson/document.h" + +namespace blink { + +class ServiceProtocol { + public: + static const fxl::StringView kScreenshotExtensionName; + static const fxl::StringView kScreenshotSkpExtensionName; + static const fxl::StringView kRunInViewExtensionName; + static const fxl::StringView kFlushUIThreadTasksExtensionName; + static const fxl::StringView kSetAssetBundlePathExtensionName; + + class Handler { + public: + struct Description { + int64_t isolate_port = 0 /* illegal port by default. */; + std::string isolate_name; + + Description() {} + + Description(int64_t p_isolate_port, std::string p_isolate_name) + : isolate_port(p_isolate_port), + isolate_name(std::move(p_isolate_name)) {} + + void Write(Handler* handler, + rapidjson::Value& value, + rapidjson::MemoryPoolAllocator<>& allocator) const; + }; + + using ServiceProtocolMap = std::map; + + virtual fxl::RefPtr GetServiceProtocolHandlerTaskRunner( + fxl::StringView method) const = 0; + + virtual Description GetServiceProtocolDescription() const = 0; + + virtual bool HandleServiceProtocolMessage( + fxl::StringView method, // one if the extension names specified above. + const ServiceProtocolMap& params, + rapidjson::Document& response) = 0; + }; + + ServiceProtocol(); + + ~ServiceProtocol(); + + void ToggleHooks(bool set); + + void AddHandler(Handler* handler); + + void RemoveHandler(Handler* handler); + + private: + const std::set endpoints_; + mutable std::mutex handlers_mutex_; + std::set handlers_; + + FXL_WARN_UNUSED_RESULT + static bool HandleMessage(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + FXL_WARN_UNUSED_RESULT + static bool HandleMessage(fxl::StringView method, + const Handler::ServiceProtocolMap& params, + ServiceProtocol* service_protocol, + rapidjson::Document& response); + FXL_WARN_UNUSED_RESULT + bool HandleMessage(fxl::StringView method, + const Handler::ServiceProtocolMap& params, + rapidjson::Document& response) const; + + FXL_WARN_UNUSED_RESULT + bool HandleListViewsMethod(rapidjson::Document& response) const; + + FXL_DISALLOW_COPY_AND_ASSIGN(ServiceProtocol); +}; + +} // namespace blink + +#endif // FLUTTER_RUNTIME_SERVICE_PROTOCOL_H_ diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index f9e25a3c8d6d7..25edcfa23bd85 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("$flutter_root/testing/testing.gni") + # Template to generate a dart embedder resource.cc file. # Required invoker inputs: # String output (name of output file) @@ -61,18 +63,18 @@ source_set("common") { "animator.h", "engine.cc", "engine.h", - "null_platform_view.cc", - "null_platform_view.h", - "null_rasterizer.cc", - "null_rasterizer.h", + "io_manager.cc", + "io_manager.h", + "isolate_configuration.cc", + "isolate_configuration.h", "picture_serializer.cc", "picture_serializer.h", "platform_view.cc", "platform_view.h", - "platform_view_service_protocol.cc", - "platform_view_service_protocol.h", "rasterizer.cc", "rasterizer.h", + "run_configuration.cc", + "run_configuration.h", "shell.cc", "shell.h", "skia_event_tracer_impl.cc", @@ -81,8 +83,8 @@ source_set("common") { "surface.h", "switches.cc", "switches.h", - "tracing_controller.cc", - "tracing_controller.h", + "thread_host.cc", + "thread_host.h", "vsync_waiter.cc", "vsync_waiter.h", "vsync_waiter_fallback.cc", @@ -90,8 +92,6 @@ source_set("common") { ] deps = [ - "//third_party/dart/runtime:dart_api", - "//third_party/dart/runtime/platform:libdart_platform", "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", @@ -99,10 +99,13 @@ source_set("common") { "$flutter_root/glue", "$flutter_root/lib/ui", "$flutter_root/runtime", + "$flutter_root/sky/engine/platform", "$flutter_root/sky/engine/wtf", "$flutter_root/synchronization", "$flutter_root/third_party/txt", "//garnet/public/lib/fxl", + "//third_party/dart/runtime:dart_api", + "//third_party/dart/runtime/platform:libdart_platform", "//third_party/rapidjson", "//third_party/skia", "//third_party/skia:gpu", @@ -112,7 +115,23 @@ source_set("common") { "//topaz/lib/tonic", ] - public_configs = [ - "$flutter_root:config", + public_configs = [ "$flutter_root:config" ] +} + +executable("shell_unittests") { + testonly = true + + sources = [ + "shell_unittests.cc", + ] + deps = [ + ":common", + "$flutter_root/fml", + "$flutter_root/lib/snapshot", + "$flutter_root/testing", + "//garnet/public/lib/fxl", + "//third_party/dart/runtime:libdart_jit", + "//third_party/skia", + "//topaz/lib/tonic", ] } diff --git a/shell/common/animator.cc b/shell/common/animator.cc index d5679a0160a86..60177a18f89ab 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -4,19 +4,18 @@ #include "flutter/shell/common/animator.h" -#include "flutter/common/threads.h" -#include "flutter/fml/trace_event.h" +#include "flutter/glue/trace_event.h" #include "lib/fxl/time/stopwatch.h" #include "third_party/dart/runtime/include/dart_tools_api.h" namespace shell { -Animator::Animator(fml::WeakPtr rasterizer, - VsyncWaiter* waiter, - Engine* engine) - : rasterizer_(rasterizer), - waiter_(waiter), - engine_(engine), +Animator::Animator(Delegate& delegate, + blink::TaskRunners task_runners, + std::unique_ptr waiter) + : delegate_(delegate), + task_runners_(std::move(task_runners)), + waiter_(std::move(waiter)), last_begin_frame_time_(), dart_frame_deadline_(0), layer_tree_pipeline_(fxl::MakeRefCounted(2)), @@ -79,7 +78,6 @@ void Animator::BeginFrame(fxl::TimePoint frame_start_time, // If we still don't have valid continuation, the pipeline is currently // full because the consumer is being too slow. Try again at the next // frame interval. - TRACE_EVENT_INSTANT0("flutter", "ConsumerSlowDefer"); RequestFrame(); return; } @@ -94,13 +92,13 @@ void Animator::BeginFrame(fxl::TimePoint frame_start_time, { TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame", FrameParity()); - engine_->BeginFrame(last_begin_frame_time_); + delegate_.OnAnimatorBeginFrame(*this, last_begin_frame_time_); } if (!frame_scheduled_) { // We don't have another frame pending, so we're waiting on user input // or I/O. Allow the Dart VM 100 ms. - engine_->NotifyIdle(dart_frame_deadline_ + 100000); + delegate_.OnAnimatorNotifyIdle(*this, dart_frame_deadline_ + 100000); } } @@ -120,15 +118,7 @@ void Animator::Render(std::unique_ptr layer_tree) { // Commit the pending continuation. producer_continuation_.Complete(std::move(layer_tree)); - blink::Threads::Gpu()->PostTask([ - rasterizer = rasterizer_, pipeline = layer_tree_pipeline_, - frame_id = FrameParity() - ]() { - if (!rasterizer.get()) - return; - TRACE_EVENT2("flutter", "GPU Workload", "mode", "basic", "frame", frame_id); - rasterizer->Draw(pipeline); - }); + delegate_.OnAnimatorDraw(*this, layer_tree_pipeline_); } bool Animator::CanReuseLastLayerTree() { @@ -137,10 +127,7 @@ bool Animator::CanReuseLastLayerTree() { void Animator::DrawLastLayerTree() { pending_frame_semaphore_.Signal(); - blink::Threads::Gpu()->PostTask([rasterizer = rasterizer_]() { - if (rasterizer.get()) - rasterizer->DrawLastLayerTree(); - }); + delegate_.OnAnimatorDrawLastLayerTree(*this); } void Animator::RequestFrame(bool regenerate_layer_tree) { @@ -164,31 +151,31 @@ void Animator::RequestFrame(bool regenerate_layer_tree) { // started an expensive operation right after posting this message however. // To support that, we need edge triggered wakes on VSync. - blink::Threads::UI()->PostTask( - [ self = weak_factory_.GetWeakPtr(), frame_number = frame_number_ ]() { - if (!self.get()) { - return; - } - TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", - frame_number); - self->AwaitVSync(); - }); + task_runners_.GetUITaskRunner()->PostTask([self = weak_factory_.GetWeakPtr(), + frame_number = frame_number_]() { + if (!self.get()) { + return; + } + TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number); + self->AwaitVSync(); + }); frame_scheduled_ = true; } void Animator::AwaitVSync() { - waiter_->AsyncWaitForVsync([self = weak_factory_.GetWeakPtr()]( - fxl::TimePoint frame_start_time, fxl::TimePoint frame_target_time) { - if (self) { - if (self->CanReuseLastLayerTree()) { - self->DrawLastLayerTree(); - } else { - self->BeginFrame(frame_start_time, frame_target_time); - } - } - }); + waiter_->AsyncWaitForVsync( + [self = weak_factory_.GetWeakPtr()](fxl::TimePoint frame_start_time, + fxl::TimePoint frame_target_time) { + if (self) { + if (self->CanReuseLastLayerTree()) { + self->DrawLastLayerTree(); + } else { + self->BeginFrame(frame_start_time, frame_target_time); + } + } + }); - engine_->NotifyIdle(dart_frame_deadline_); + delegate_.OnAnimatorNotifyIdle(*this, dart_frame_deadline_); } } // namespace shell diff --git a/shell/common/animator.h b/shell/common/animator.h index bc2ee21441b29..53b2ac6884158 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -5,7 +5,7 @@ #ifndef FLUTTER_SHELL_COMMON_ANIMATOR_H_ #define FLUTTER_SHELL_COMMON_ANIMATOR_H_ -#include "flutter/shell/common/engine.h" +#include "flutter/common/task_runners.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/vsync_waiter.h" #include "flutter/synchronization/pipeline.h" @@ -16,17 +16,28 @@ namespace shell { -class Animator { +class Animator final { public: - Animator(fml::WeakPtr rasterizer, - VsyncWaiter* waiter, - Engine* engine); + class Delegate { + public: + virtual void OnAnimatorBeginFrame(const Animator& animator, + fxl::TimePoint frame_time) = 0; - ~Animator(); + virtual void OnAnimatorNotifyIdle(const Animator& animator, + int64_t deadline) = 0; + + virtual void OnAnimatorDraw( + const Animator& animator, + fxl::RefPtr> pipeline) = 0; + + virtual void OnAnimatorDrawLastLayerTree(const Animator& animator) = 0; + }; - void set_rasterizer(fml::WeakPtr rasterizer) { - rasterizer_ = rasterizer; - } + Animator(Delegate& delegate, + blink::TaskRunners task_runners, + std::unique_ptr waiter); + + ~Animator(); void RequestFrame(bool regenerate_layer_tree = true); @@ -51,9 +62,9 @@ class Animator { const char* FrameParity(); - fml::WeakPtr rasterizer_; - VsyncWaiter* waiter_; - Engine* engine_; + Delegate& delegate_; + blink::TaskRunners task_runners_; + std::unique_ptr waiter_; fxl::TimePoint last_begin_frame_time_; int64_t dart_frame_deadline_; @@ -67,7 +78,7 @@ class Animator { bool dimension_change_pending_; SkISize last_layer_tree_size_; - fml::WeakPtrFactory weak_factory_; + fxl::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(Animator); }; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 3629b729c29f7..3d6fd496d3fa9 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -4,47 +4,20 @@ #include "flutter/shell/common/engine.h" -#if OS(WIN) -#include -#include -#define access _access -#define R_OK 0x4 - -#ifndef S_ISDIR -#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) -#endif - -#ifndef S_ISREG -#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) -#endif - -#else -#include -#include -#include -#endif // OS(WIN) - -#include -#include #include #include -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/assets/unzipper_provider.h" -#include "flutter/assets/zip_asset_store.h" -#include "flutter/assets/asset_provider.h" #include "flutter/common/settings.h" -#include "flutter/common/threads.h" #include "flutter/glue/trace_event.h" #include "flutter/lib/snapshot/snapshot.h" #include "flutter/lib/ui/text/font_collection.h" #include "flutter/runtime/asset_font_selector.h" -#include "flutter/runtime/dart_controller.h" -#include "flutter/runtime/dart_init.h" -#include "flutter/runtime/runtime_init.h" +#include "flutter/runtime/platform_impl.h" #include "flutter/runtime/test_font_selector.h" #include "flutter/shell/common/animator.h" #include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/shell.h" +#include "flutter/sky/engine/platform/fonts/FontFallbackList.h" #include "flutter/sky/engine/public/web/Sky.h" #include "lib/fxl/files/eintr_wrapper.h" #include "lib/fxl/files/file.h" @@ -55,380 +28,208 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" -namespace shell { -namespace { - -constexpr char kAssetChannel[] = "flutter/assets"; -constexpr char kLifecycleChannel[] = "flutter/lifecycle"; -constexpr char kNavigationChannel[] = "flutter/navigation"; -constexpr char kLocalizationChannel[] = "flutter/localization"; -constexpr char kSettingsChannel[] = "flutter/settings"; - -#if OS(WIN) -void FindAndReplaceInPlace(std::string& str, - const std::string& findStr, - const std::string& replaceStr) { - size_t pos = 0; - while ((pos = str.find(findStr, pos)) != std::string::npos) { - str.replace(pos, findStr.length(), replaceStr); - pos += replaceStr.length(); - } -} -#endif - -std::string SanitizePath(const std::string& path) { -#if OS(WIN) - std::string sanitized = path; - FindAndReplaceInPlace(sanitized, "\\\\", "/"); - if ((sanitized.length() > 2) && (sanitized[1] == ':')) { - // Path begins with a drive letter. - sanitized = '/' + sanitized; - } - return sanitized; -#else - return path; +#ifdef ERROR +#undef ERROR #endif -} - -bool PathExists(const std::string& path) { - return access(path.c_str(), R_OK) == 0; -} - -std::string FindPackagesPath(const std::string& main_dart) { - std::string directory = files::GetDirectoryName(main_dart); - std::string packages_path = directory + "/.packages"; - if (!PathExists(packages_path)) { - directory = files::GetDirectoryName(directory); - packages_path = directory + "/.packages"; - if (!PathExists(packages_path)) - packages_path = std::string(); - } - return packages_path; -} -std::string GetScriptUriFromPath(const std::string& path) { - return "file://" + SanitizePath(path); -} - -} // namespace +namespace shell { -Engine::Engine(PlatformView* platform_view) - : platform_view_(platform_view->GetWeakPtr()), - animator_(std::make_unique( - platform_view->rasterizer().GetWeakRasterizerPtr(), - platform_view->GetVsyncWaiter(), - this)), +static constexpr char kAssetChannel[] = "flutter/assets"; +static constexpr char kLifecycleChannel[] = "flutter/lifecycle"; +static constexpr char kNavigationChannel[] = "flutter/navigation"; +static constexpr char kLocalizationChannel[] = "flutter/localization"; +static constexpr char kSettingsChannel[] = "flutter/settings"; + +Engine::Engine(Delegate& delegate, + const blink::DartVM& vm, + blink::TaskRunners task_runners, + blink::Settings settings, + std::unique_ptr animator, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue) + : delegate_(delegate), + settings_(std::move(settings)), + animator_(std::move(animator)), + legacy_sky_platform_(settings_.using_blink ? new blink::PlatformImpl() + : nullptr), load_script_error_(tonic::kNoError), - user_settings_data_("{}"), activity_running_(false), have_surface_(false), - weak_factory_(this) {} + weak_factory_(this) { + weak_prototype_ = weak_factory_.GetWeakPtr(); -Engine::~Engine() {} + if (legacy_sky_platform_) { + // TODO: Remove this legacy call along with the platform. This is what makes + // the engine unable to run from multiple threads in the legacy + // configuration. + blink::InitEngine(legacy_sky_platform_.get()); + } -void Engine::set_rasterizer(fml::WeakPtr rasterizer) { - animator_->set_rasterizer(rasterizer); + // Runtime controller is initialized here because it takes a reference to this + // object as its delegate. The delegate may be called in the constructor and + // we want to be fully initilazed by that point. + runtime_controller_ = std::make_unique( + *this, // runtime delegate + &vm, // VM + std::move(task_runners), // task runners + std::move(resource_context), // resource context + std::move(unref_queue) // skia unref queue + ); } -fml::WeakPtr Engine::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); +Engine::~Engine() { + if (legacy_sky_platform_) { + blink::ShutdownEngine(/* legacy_sky_platform_ */); + } } -#if !FLUTTER_AOT -#elif OS(IOS) -#elif OS(ANDROID) -// TODO(bkonyi): do we even get here for Windows? -static const uint8_t* MemMapSnapshot(const std::string& aot_snapshot_path, - const std::string& default_file_name, - const std::string& settings_file_name, - bool executable) { - std::string asset_path; - if (settings_file_name.empty()) { - asset_path = aot_snapshot_path + "/" + default_file_name; - } else { - asset_path = aot_snapshot_path + "/" + settings_file_name; +fml::WeakPtr Engine::GetWeakPtr() const { + return weak_prototype_; +} + +bool Engine::UpdateAssetManager( + fxl::RefPtr new_asset_manager) { + if (asset_manager_ == new_asset_manager) { + return false; } -#if OS(WIN) - HANDLE file_handle_ = - CreateFileA(reinterpret_cast(path.c_str()), GENERIC_READ, - FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr); + asset_manager_ = new_asset_manager; - if (file_handle_ == INVALID_HANDLE_VALUE) { - return; + if (!asset_manager_) { + return false; } - size_ = GetFileSize(file_handle_, nullptr); - if (size_ == INVALID_FILE_SIZE) { - size_ = 0; - return; + if (settings_.using_blink) { + // Using blink as the text engine. + blink::FontFallbackList::SetUseTestFonts(settings_.use_test_fonts); + } else { + // Using libTXT as the text engine. + if (settings_.use_test_fonts) { + blink::FontCollection::ForProcess().RegisterTestFonts(); + } else { + blink::FontCollection::ForProcess().RegisterFonts(*asset_manager_.get()); + } } - int mapping_flags = executable ? PAGE_EXECUTE_READ : PAGE_READONLY; - mapping_handle_ = CreateFileMapping(file_handle_, nullptr, mapping_flags, 0, - size_, nullptr); - - CloseHandle(file_handle_); + return true; +} - if (mapping_handle_ == INVALID_HANDLE_VALUE) { - return; +bool Engine::Restart(RunConfiguration configuration) { + TRACE_EVENT0("flutter", "Engine::Restart"); + if (!configuration.IsValid()) { + FXL_LOG(ERROR) << "Engine run configuration was invalid."; + return false; } + runtime_controller_ = runtime_controller_->Clone(); + UpdateAssetManager(nullptr); + return Run(std::move(configuration)); +} - int access_flags = FILE_MAP_READ; - if (executable) { - access_flags |= FILE_MAP_EXECUTE; +bool Engine::Run(RunConfiguration configuration) { + if (!configuration.IsValid()) { + FXL_LOG(ERROR) << "Engine run configuration was invalid."; + return false; } - auto mapping = MapViewOfFile(mapping_handle_, access_flags, 0, 0, size_); - if (mapping == INVALID_HANDLE_VALUE) { - CloseHandle(mapping_handle_); - mapping_handle_ = INVALID_HANDLE_VALUE; - return; + if (!PrepareAndLaunchIsolate(std::move(configuration))) { + return false; } - void* symbol = static_cast(mapping); - if (symbol == NULL) { - return nullptr; - } -#else - struct stat info; - if (stat(asset_path.c_str(), &info) < 0) { - return nullptr; - } - int64_t asset_size = info.st_size; + auto isolate = runtime_controller_->GetRootIsolate(); - fxl::UniqueFD fd(HANDLE_EINTR(open(asset_path.c_str(), O_RDONLY))); - if (fd.get() == -1) { - return nullptr; - } + bool isolate_running = + isolate && isolate->GetPhase() == blink::DartIsolate::Phase::Running; - int mmap_flags = PROT_READ; - if (executable) - mmap_flags |= PROT_EXEC; + if (isolate_running) { + tonic::DartState::Scope scope(isolate.get()); - void* symbol = mmap(NULL, asset_size, mmap_flags, MAP_PRIVATE, fd.get(), 0); - if (symbol == MAP_FAILED) { - return nullptr; - } -#endif - return reinterpret_cast(symbol); -} -#endif + if (settings_.root_isolate_create_callback) { + settings_.root_isolate_create_callback(); + } -static const uint8_t* default_isolate_snapshot_data = nullptr; -static const uint8_t* default_isolate_snapshot_instr = nullptr; - -void Engine::Init(const std::string& bundle_path) { - const uint8_t* vm_snapshot_data; - const uint8_t* vm_snapshot_instr; -#if !FLUTTER_AOT - vm_snapshot_data = ::kDartVmSnapshotData; - vm_snapshot_instr = ::kDartVmSnapshotInstructions; - default_isolate_snapshot_data = ::kDartIsolateCoreSnapshotData; - default_isolate_snapshot_instr = ::kDartIsolateCoreSnapshotInstructions; -#elif OS(IOS) - const char* kDartApplicationLibraryPath = "App.framework/App"; - const char* application_library_path = kDartApplicationLibraryPath; - const blink::Settings& settings = blink::Settings::Get(); - const std::string& application_library_path_setting = - settings.application_library_path; - if (!application_library_path_setting.empty()) { - application_library_path = application_library_path_setting.c_str(); - } - dlerror(); // clear previous errors on thread - void* library_handle = dlopen(application_library_path, RTLD_NOW); - const char* err = dlerror(); - if (err != nullptr) { - FXL_LOG(FATAL) << "dlopen failed: " << err; - } - vm_snapshot_data = reinterpret_cast( - dlsym(library_handle, "kDartVmSnapshotData")); - vm_snapshot_instr = reinterpret_cast( - dlsym(library_handle, "kDartVmSnapshotInstructions")); - default_isolate_snapshot_data = reinterpret_cast( - dlsym(library_handle, "kDartIsolateSnapshotData")); - default_isolate_snapshot_instr = reinterpret_cast( - dlsym(library_handle, "kDartIsolateSnapshotInstructions")); -#elif OS(ANDROID) || OS(WIN) - const blink::Settings& settings = blink::Settings::Get(); - const std::string& aot_shared_library_path = settings.aot_shared_library_path; - const std::string& aot_snapshot_path = settings.aot_snapshot_path; - - if (!aot_shared_library_path.empty()) { - FXL_CHECK(aot_snapshot_path.empty()); - dlerror(); // clear previous errors on thread - void* library_handle = dlopen(aot_shared_library_path.c_str(), RTLD_NOW); - const char* err = dlerror(); - if (err != nullptr) { - FXL_LOG(FATAL) << "dlopen failed: " << err; + if (settings_.root_isolate_shutdown_callback) { + isolate->AddIsolateShutdownCallback( + settings_.root_isolate_shutdown_callback); + } + + // Blink uses a per isolate font selector. + if (settings_.using_blink) { + if (settings_.use_test_fonts) { + blink::TestFontSelector::Install(); + } else { + blink::AssetFontSelector::Install(asset_manager_); + } } - vm_snapshot_data = reinterpret_cast( - dlsym(library_handle, "_kDartVmSnapshotData")); - vm_snapshot_instr = reinterpret_cast( - dlsym(library_handle, "_kDartVmSnapshotInstructions")); - default_isolate_snapshot_data = reinterpret_cast( - dlsym(library_handle, "_kDartIsolateSnapshotData")); - default_isolate_snapshot_instr = reinterpret_cast( - dlsym(library_handle, "_kDartIsolateSnapshotInstructions")); - } else { - FXL_CHECK(!aot_snapshot_path.empty()); - vm_snapshot_data = - MemMapSnapshot(aot_snapshot_path, "vm_snapshot_data", - settings.aot_vm_snapshot_data_filename, false); - vm_snapshot_instr = - MemMapSnapshot(aot_snapshot_path, "vm_snapshot_instr", - settings.aot_vm_snapshot_instr_filename, true); - default_isolate_snapshot_data = - MemMapSnapshot(aot_snapshot_path, "isolate_snapshot_data", - settings.aot_isolate_snapshot_data_filename, false); - default_isolate_snapshot_instr = - MemMapSnapshot(aot_snapshot_path, "isolate_snapshot_instr", - settings.aot_isolate_snapshot_instr_filename, true); } -#else -#error Unknown OS -#endif - blink::InitRuntime(vm_snapshot_data, vm_snapshot_instr, - default_isolate_snapshot_data, - default_isolate_snapshot_instr, bundle_path); + + return isolate_running; } -const std::string Engine::main_entrypoint_ = "main"; +bool Engine::PrepareAndLaunchIsolate(RunConfiguration configuration) { + TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate"); -void Engine::RunBundle(const std::string& bundle_path, - const std::string& entrypoint, - bool reuse_runtime_controller) { - TRACE_EVENT0("flutter", "Engine::RunBundle"); - ConfigureAssetBundle(bundle_path); - DoRunBundle(GetScriptUriFromPath(bundle_path), entrypoint, - reuse_runtime_controller); -} + UpdateAssetManager(configuration.GetAssetManager()); -void Engine::DoRunBundle(const std::string& script_uri, - const std::string& entrypoint, - bool reuse_runtime_controller) { - ConfigureRuntime(script_uri, reuse_runtime_controller); - if (blink::IsRunningPrecompiledCode()) { - runtime_->dart_controller()->RunFromPrecompiledSnapshot(entrypoint); - } else { - std::vector kernel; - if (GetAssetAsBuffer(blink::kKernelAssetKey, &kernel)) { - runtime_->dart_controller()->RunFromKernel(kernel, entrypoint); - return; - } - std::vector snapshot; - if (!GetAssetAsBuffer(blink::kSnapshotAssetKey, &snapshot)) - return; - runtime_->dart_controller()->RunFromScriptSnapshot( - snapshot.data(), snapshot.size(), entrypoint); + auto isolate_configuration = configuration.TakeIsolateConfiguration(); + + auto isolate = runtime_controller_->GetRootIsolate(); + + if (!isolate_configuration->PrepareIsolate(isolate)) { + FXL_DLOG(ERROR) << "Could not prepare to run the isolate."; + return false; } -} -// TODO(jsimmons): merge this with RunBundle -void Engine::RunBundleWithAssets( - fxl::RefPtr asset_provider, - const std::string& bundle_path, - const std::string& entrypoint, - bool reuse_runtime_controller) { - TRACE_EVENT0("flutter", "Engine::RunBundleWithAssets"); - asset_provider_ = asset_provider; - DoRunBundle(GetScriptUriFromPath(bundle_path), entrypoint, - reuse_runtime_controller); -} - -void Engine::RunBundleAndSource(const std::string& bundle_path, - const std::string& main, - const std::string& packages, - bool reuse_runtime_controller) { - TRACE_EVENT0("flutter", "Engine::RunBundleAndSource"); - FXL_CHECK(!blink::IsRunningPrecompiledCode()) - << "Cannot run from source in a precompiled build."; - std::string packages_path = packages; - if (packages_path.empty()) - packages_path = FindPackagesPath(main); - - if (!bundle_path.empty()) - ConfigureAssetBundle(bundle_path); - - ConfigureRuntime(main, reuse_runtime_controller); - - if (blink::GetKernelPlatformBinary() != nullptr) { - std::vector kernel; - if (!files::ReadFileToVector(main, &kernel)) { - load_script_error_ = tonic::kUnknownErrorType; - } - load_script_error_ = runtime_->dart_controller()->RunFromKernel(kernel); - } else { - load_script_error_ = - runtime_->dart_controller()->RunFromSource(main, packages_path); + if (!isolate->Run(configuration.GetEntrypoint())) { + FXL_DLOG(ERROR) << "Could not run the isolate."; + return false; } + + return true; } void Engine::BeginFrame(fxl::TimePoint frame_time) { TRACE_EVENT0("flutter", "Engine::BeginFrame"); - if (runtime_) - runtime_->BeginFrame(frame_time); + runtime_controller_->BeginFrame(frame_time); } void Engine::NotifyIdle(int64_t deadline) { TRACE_EVENT0("flutter", "Engine::NotifyIdle"); - if (runtime_) - runtime_->NotifyIdle(deadline); -} - -void Engine::RunFromSource(const std::string& main, - const std::string& packages, - const std::string& bundle_path) { - RunBundleAndSource(bundle_path, main, packages); + runtime_controller_->NotifyIdle(deadline); } -void Engine::SetAssetBundlePath(const std::string& bundle_path) { - TRACE_EVENT0("flutter", "Engine::SetAssetBundlePath"); - ConfigureAssetBundle(bundle_path); +std::pair Engine::GetUIIsolateReturnCode() { + return runtime_controller_->GetRootIsolateReturnCode(); } Dart_Port Engine::GetUIIsolateMainPort() { - if (!runtime_) - return ILLEGAL_PORT; - return runtime_->GetMainPort(); + return runtime_controller_->GetMainPort(); } std::string Engine::GetUIIsolateName() { - if (!runtime_) { - return ""; - } - return runtime_->GetIsolateName(); + return runtime_controller_->GetIsolateName(); } bool Engine::UIIsolateHasLivePorts() { - if (!runtime_) - return false; - return runtime_->HasLivePorts(); + return runtime_controller_->HasLivePorts(); } tonic::DartErrorHandleType Engine::GetUIIsolateLastError() { - if (!runtime_) - return tonic::kNoError; - return runtime_->GetLastError(); + return runtime_controller_->GetLastError(); } tonic::DartErrorHandleType Engine::GetLoadScriptError() { return load_script_error_; } -void Engine::OnOutputSurfaceCreated(const fxl::Closure& gpu_continuation) { - blink::Threads::Gpu()->PostTask(gpu_continuation); +void Engine::OnOutputSurfaceCreated() { have_surface_ = true; StartAnimatorIfPossible(); - if (runtime_) - ScheduleFrame(); + ScheduleFrame(); } -void Engine::OnOutputSurfaceDestroyed(const fxl::Closure& gpu_continuation) { +void Engine::OnOutputSurfaceDestroyed() { have_surface_ = false; StopAnimator(); - blink::Threads::Gpu()->PostTask(gpu_continuation); } void Engine::SetViewportMetrics(const blink::ViewportMetrics& metrics) { @@ -436,8 +237,7 @@ void Engine::SetViewportMetrics(const blink::ViewportMetrics& metrics) { viewport_metrics_.physical_height != metrics.physical_height || viewport_metrics_.physical_width != metrics.physical_width; viewport_metrics_ = metrics; - if (runtime_) - runtime_->SetViewportMetrics(viewport_metrics_); + runtime_controller_->SetViewportMetrics(viewport_metrics_); if (animator_) { if (dimensions_changed) animator_->SetDimensionChangePending(); @@ -459,8 +259,7 @@ void Engine::DispatchPlatformMessage( return; } - if (runtime_) { - runtime_->DispatchPlatformMessage(std::move(message)); + if (runtime_controller_->DispatchPlatformMessage(std::move(message))) { return; } @@ -493,7 +292,6 @@ bool Engine::HandleLifecyclePlatformMessage(blink::PlatformMessage* message) { bool Engine::HandleNavigationPlatformMessage( fxl::RefPtr message) { - FXL_DCHECK(!runtime_); const auto& data = message->data(); rapidjson::Document document; @@ -532,99 +330,33 @@ bool Engine::HandleLocalizationPlatformMessage( if (!language.IsString() || !country.IsString()) return false; - language_code_ = language.GetString(); - country_code_ = country.GetString(); - if (runtime_) - runtime_->SetLocale(language_code_, country_code_); - return true; + return runtime_controller_->SetLocale(language.GetString(), + country.GetString()); } void Engine::HandleSettingsPlatformMessage(blink::PlatformMessage* message) { const auto& data = message->data(); std::string jsonData(reinterpret_cast(data.data()), data.size()); - user_settings_data_ = jsonData; - if (runtime_) { - runtime_->SetUserSettingsData(user_settings_data_); - if (have_surface_) - ScheduleFrame(); + if (runtime_controller_->SetUserSettingsData(std::move(jsonData)) && + have_surface_) { + ScheduleFrame(); } } -void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet) { - if (runtime_) - runtime_->DispatchPointerDataPacket(packet); +void Engine::DispatchPointerDataPacket(const blink::PointerDataPacket& packet) { + runtime_controller_->DispatchPointerDataPacket(packet); } void Engine::DispatchSemanticsAction(int id, blink::SemanticsAction action, std::vector args) { - if (runtime_) - runtime_->DispatchSemanticsAction(id, action, std::move(args)); + runtime_controller_->DispatchSemanticsAction(id, action, std::move(args)); } void Engine::SetSemanticsEnabled(bool enabled) { - semantics_enabled_ = enabled; - if (runtime_) - runtime_->SetSemanticsEnabled(semantics_enabled_); -} - -void Engine::ConfigureAssetBundle(const std::string& path) { - asset_provider_ = fxl::MakeRefCounted(path); - - struct stat stat_result = {}; - - // TODO(abarth): We should reset directory_asset_bundle_, but that might break - // custom font loading in hot reload. - - if (::stat(path.c_str(), &stat_result) != 0) { - FXL_LOG(INFO) << "Could not configure asset bundle at path: " << path; - return; - } - - std::string flx_path; - if (S_ISDIR(stat_result.st_mode)) { - flx_path = files::GetDirectoryName(path) + "/app.flx"; - } else if (S_ISREG(stat_result.st_mode)) { - flx_path = path; - } - - if (PathExists(flx_path)) { - asset_store_ = fxl::MakeRefCounted( - blink::GetUnzipperProviderForPath(flx_path)); - } -} - -void Engine::ConfigureRuntime(const std::string& script_uri, - bool reuse_runtime_controller) { - if (runtime_ && reuse_runtime_controller) { - return; - } - runtime_ = blink::RuntimeController::Create(this); - runtime_->CreateDartController(std::move(script_uri), - default_isolate_snapshot_data, - default_isolate_snapshot_instr); - runtime_->SetViewportMetrics(viewport_metrics_); - runtime_->SetLocale(language_code_, country_code_); - runtime_->SetUserSettingsData(user_settings_data_); - runtime_->SetSemanticsEnabled(semantics_enabled_); -} - -void Engine::DidCreateMainIsolate(Dart_Isolate isolate) { - if (blink::Settings::Get().use_test_fonts) { - blink::TestFontSelector::Install(); - if (!blink::Settings::Get().using_blink) - blink::FontCollection::ForProcess().RegisterTestFonts(); - } else if (asset_provider_) { - blink::AssetFontSelector::Install(asset_provider_); - if (!blink::Settings::Get().using_blink) { - blink::FontCollection::ForProcess().RegisterFontsFromAssetProvider( - asset_provider_); - } - } + runtime_controller_->SetSemanticsEnabled(enabled); } -void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {} - void Engine::StopAnimator() { animator_->Stop(); } @@ -659,49 +391,34 @@ void Engine::Render(std::unique_ptr layer_tree) { } void Engine::UpdateSemantics(blink::SemanticsNodeUpdates update) { - blink::Threads::Platform()->PostTask(fxl::MakeCopyable([ - platform_view = platform_view_.lock(), update = std::move(update) - ]() mutable { - if (platform_view) - platform_view->UpdateSemantics(std::move(update)); - })); + delegate_.OnEngineUpdateSemantics(*this, std::move(update)); } void Engine::HandlePlatformMessage( fxl::RefPtr message) { if (message->channel() == kAssetChannel) { HandleAssetPlatformMessage(std::move(message)); - return; + } else { + delegate_.OnEngineHandlePlatformMessage(*this, std::move(message)); } - blink::Threads::Platform()->PostTask([ - platform_view = platform_view_.lock(), message = std::move(message) - ]() mutable { - if (platform_view) - platform_view->HandlePlatformMessage(std::move(message)); - }); } void Engine::HandleAssetPlatformMessage( fxl::RefPtr message) { fxl::RefPtr response = message->response(); - if (!response) + if (!response) { return; + } const auto& data = message->data(); std::string asset_name(reinterpret_cast(data.data()), data.size()); + std::vector asset_data; - if (GetAssetAsBuffer(asset_name, &asset_data)) { + if (asset_manager_ && asset_manager_->GetAsBuffer(asset_name, &asset_data)) { response->Complete(std::move(asset_data)); } else { response->CompleteEmpty(); } } -bool Engine::GetAssetAsBuffer(const std::string& name, - std::vector* data) { - return ((asset_provider_ && - asset_provider_->GetAsBuffer(name, data)) || - (asset_store_ && asset_store_->GetAsBuffer(name, data))); -} - } // namespace shell diff --git a/shell/common/engine.h b/shell/common/engine.h index a0c5183338a43..ede442ee3e8a4 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -5,131 +5,144 @@ #ifndef SHELL_COMMON_ENGINE_H_ #define SHELL_COMMON_ENGINE_H_ -#include "flutter/assets/zip_asset_store.h" -#include "flutter/assets/asset_provider.h" +#include +#include + +#include "flutter/assets/asset_manager.h" +#include "flutter/common/task_runners.h" +#include "flutter/lib/ui/semantics/semantics_node.h" #include "flutter/lib/ui/window/platform_message.h" #include "flutter/lib/ui/window/viewport_metrics.h" +#include "flutter/runtime/dart_vm.h" +#include "flutter/runtime/platform_impl.h" #include "flutter/runtime/runtime_controller.h" #include "flutter/runtime/runtime_delegate.h" +#include "flutter/shell/common/animator.h" #include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/run_configuration.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/weak_ptr.h" #include "third_party/skia/include/core/SkPicture.h" -namespace blink { -class DirectoryAssetBundle; -class ZipAssetBundle; -} // namespace blink - namespace shell { -class PlatformView; -class Animator; -using PointerDataPacket = blink::PointerDataPacket; -class Engine : public blink::RuntimeDelegate { +class Engine final : public blink::RuntimeDelegate { public: - explicit Engine(PlatformView* platform_view); + class Delegate { + public: + virtual void OnEngineUpdateSemantics( + const Engine& engine, + blink::SemanticsNodeUpdates update) = 0; + + virtual void OnEngineHandlePlatformMessage( + const Engine& engine, + fxl::RefPtr message) = 0; + }; + + Engine(Delegate& delegate, + const blink::DartVM& vm, + blink::TaskRunners task_runners, + blink::Settings settings, + std::unique_ptr animator, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue); ~Engine() override; - fml::WeakPtr GetWeakPtr(); - - static void Init(const std::string& bundle_path); + fml::WeakPtr GetWeakPtr() const; - void RunBundle(const std::string& bundle_path, - const std::string& entrypoint = main_entrypoint_, - bool reuse_runtime_controller = false); + FXL_WARN_UNUSED_RESULT + bool Run(RunConfiguration configuration); - // Uses the given provider to locate assets. - void RunBundleWithAssets(fxl::RefPtr asset_provider, - const std::string& bundle_path, - const std::string& entrypoint = main_entrypoint_, - bool reuse_runtime_controller = false); + // Used to "cold reload" a running application where the shell (along with the + // platform view and its rasterizer bindings) remains the same but the root + // isolate is torn down and restarted with the new configuration. Only used in + // the development workflow. + FXL_WARN_UNUSED_RESULT + bool Restart(RunConfiguration configuration); - // Uses the given source code instead of looking inside the bundle for the - // source code. - void RunBundleAndSource(const std::string& bundle_path, - const std::string& main, - const std::string& packages, - bool reuse_runtime_controller = false); + bool UpdateAssetManager(fxl::RefPtr asset_manager); void BeginFrame(fxl::TimePoint frame_time); - void NotifyIdle(int64_t deadline); - void RunFromSource(const std::string& main, - const std::string& packages, - const std::string& bundle); - void SetAssetBundlePath(const std::string& bundle_path); + void NotifyIdle(int64_t deadline); Dart_Port GetUIIsolateMainPort(); + std::string GetUIIsolateName(); + bool UIIsolateHasLivePorts(); + tonic::DartErrorHandleType GetUIIsolateLastError(); + tonic::DartErrorHandleType GetLoadScriptError(); - void OnOutputSurfaceCreated(const fxl::Closure& gpu_continuation); - void OnOutputSurfaceDestroyed(const fxl::Closure& gpu_continuation); + std::pair GetUIIsolateReturnCode(); + + void OnOutputSurfaceCreated(); + + void OnOutputSurfaceDestroyed(); + void SetViewportMetrics(const blink::ViewportMetrics& metrics); + void DispatchPlatformMessage(fxl::RefPtr message); - void DispatchPointerDataPacket(const PointerDataPacket& packet); + + void DispatchPointerDataPacket(const blink::PointerDataPacket& packet); + void DispatchSemanticsAction(int id, blink::SemanticsAction action, std::vector args); + void SetSemanticsEnabled(bool enabled); - void ScheduleFrame(bool regenerate_layer_tree = true) override; - void set_rasterizer(fml::WeakPtr rasterizer); + void ScheduleFrame(bool regenerate_layer_tree = true) override; private: - // RuntimeDelegate methods: + Engine::Delegate& delegate_; + const blink::Settings settings_; + std::unique_ptr animator_; + std::unique_ptr runtime_controller_; + std::unique_ptr legacy_sky_platform_; + tonic::DartErrorHandleType load_script_error_; + std::string initial_route_; + blink::ViewportMetrics viewport_metrics_; + fxl::RefPtr asset_manager_; + bool activity_running_; + bool have_surface_; + fml::WeakPtr weak_prototype_; + fml::WeakPtrFactory weak_factory_; + + // |blink::RuntimeDelegate| std::string DefaultRouteName() override; + + // |blink::RuntimeDelegate| void Render(std::unique_ptr layer_tree) override; + + // |blink::RuntimeDelegate| void UpdateSemantics(blink::SemanticsNodeUpdates update) override; + + // |blink::RuntimeDelegate| void HandlePlatformMessage( fxl::RefPtr message) override; - void DidCreateMainIsolate(Dart_Isolate isolate) override; - void DidCreateSecondaryIsolate(Dart_Isolate isolate) override; void StopAnimator(); - void StartAnimatorIfPossible(); - - void DoRunBundle(const std::string& script_uri, - const std::string& entrypoint, - bool reuse_runtime_controller); - void ConfigureAssetBundle(const std::string& path); - void ConfigureRuntime(const std::string& script_uri, - bool reuse_runtime_controller = false); + void StartAnimatorIfPossible(); bool HandleLifecyclePlatformMessage(blink::PlatformMessage* message); + bool HandleNavigationPlatformMessage( fxl::RefPtr message); + bool HandleLocalizationPlatformMessage(blink::PlatformMessage* message); + void HandleSettingsPlatformMessage(blink::PlatformMessage* message); void HandleAssetPlatformMessage(fxl::RefPtr message); - bool GetAssetAsBuffer(const std::string& name, std::vector* data); - static const std::string main_entrypoint_; + bool GetAssetAsBuffer(const std::string& name, std::vector* data); - fxl::RefPtr asset_provider_; - std::weak_ptr platform_view_; - std::unique_ptr animator_; - std::unique_ptr runtime_; - tonic::DartErrorHandleType load_script_error_; - std::string initial_route_; - blink::ViewportMetrics viewport_metrics_; - std::string language_code_; - std::string country_code_; - std::string user_settings_data_; - bool semantics_enabled_ = false; - // TODO(zarah): Remove usage of asset_store_ once app.flx is removed. - fxl::RefPtr asset_store_; - fxl::RefPtr directory_asset_bundle_; - // TODO(eseidel): This should move into an AnimatorStateMachine. - bool activity_running_; - bool have_surface_; - fml::WeakPtrFactory weak_factory_; + bool PrepareAndLaunchIsolate(RunConfiguration configuration); FXL_DISALLOW_COPY_AND_ASSIGN(Engine); }; diff --git a/shell/common/io_manager.cc b/shell/common/io_manager.cc new file mode 100644 index 0000000000000..4161422978fcf --- /dev/null +++ b/shell/common/io_manager.cc @@ -0,0 +1,73 @@ +// 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/shell/common/io_manager.h" + +#include "flutter/fml/message_loop.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" + +namespace shell { + +sk_sp IOManager::CreateCompatibleResourceLoadingContext( + GrBackend backend) { + if (backend != GrBackend::kOpenGL_GrBackend) { + return nullptr; + } + + GrContextOptions options = {}; + + // There is currently a bug with doing GPU YUV to RGB conversions on the IO + // thread. The necessary work isn't being flushed or synchronized with the + // other threads correctly, so the textures end up blank. For now, suppress + // that feature, which will cause texture uploads to do CPU YUV conversion. + options.fDisableGpuYUVConversion = true; + + if (auto context = GrContext::MakeGL(GrGLMakeNativeInterface(), options)) { + // Do not cache textures created by the image decoder. These textures + // should be deleted when they are no longer referenced by an SkImage. + context->setResourceCacheLimits(0, 0); + return context; + } + + return nullptr; +} + +IOManager::IOManager(sk_sp resource_context, + fxl::RefPtr unref_queue_task_runner) + : resource_context_(std::move(resource_context)), + resource_context_weak_factory_( + resource_context_ ? std::make_unique>( + resource_context_.get()) + : nullptr), + unref_queue_(fxl::MakeRefCounted( + std::move(unref_queue_task_runner), + fxl::TimeDelta::FromMilliseconds(250))), + weak_factory_(this) { + if (!resource_context_) { + FXL_DLOG(WARNING) << "The IO manager was initialized without a resource " + "context. Async texture uploads will be disabled. " + "Expect performance degradation."; + } + + if (resource_context_weak_factory_) { + resource_context_weak_prototype_ = + resource_context_weak_factory_->GetWeakPtr(); + } +} + +IOManager::~IOManager() { + // Last chance to drain the IO queue as the platform side reference to the + // underlying OpenGL context may be going away. + unref_queue_->Drain(); +} + +fml::WeakPtr IOManager::GetResourceContext() const { + return resource_context_weak_prototype_; +} + +fxl::RefPtr IOManager::GetSkiaUnrefQueue() const { + return unref_queue_; +} + +} // namespace shell diff --git a/shell/common/io_manager.h b/shell/common/io_manager.h new file mode 100644 index 0000000000000..1077a28d0ae36 --- /dev/null +++ b/shell/common/io_manager.h @@ -0,0 +1,52 @@ +// 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_SHELL_COMMON_IO_MANAGER_H_ +#define FLUTTER_SHELL_COMMON_IO_MANAGER_H_ + +#include + +#include "flutter/flow/skia_gpu_object.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" +#include "third_party/skia/include/gpu/GrContext.h" + +namespace shell { + +class IOManager { + public: + // Convenience methods for platforms to create a GrContext used to supply to + // the IOManager. The platforms may create the context themselves if they so + // desire. + static sk_sp CreateCompatibleResourceLoadingContext( + GrBackend backend); + + IOManager(sk_sp resource_context, + fxl::RefPtr unref_queue_task_runner); + + ~IOManager(); + + fml::WeakPtr GetResourceContext() const; + + fxl::RefPtr GetSkiaUnrefQueue() const; + + private: + // Resource context management. + sk_sp resource_context_; + fml::WeakPtr resource_context_weak_prototype_; + std::unique_ptr> + resource_context_weak_factory_; + + // Unref queue management. + fxl::RefPtr unref_queue_; + + fml::WeakPtrFactory weak_factory_; + + FXL_DISALLOW_COPY_AND_ASSIGN(IOManager); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_COMMON_IO_MANAGER_H_ diff --git a/shell/common/isolate_configuration.cc b/shell/common/isolate_configuration.cc new file mode 100644 index 0000000000000..0706ee5ab58df --- /dev/null +++ b/shell/common/isolate_configuration.cc @@ -0,0 +1,144 @@ +// 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/shell/common/isolate_configuration.h" + +#include "flutter/runtime/dart_vm.h" + +namespace shell { + +IsolateConfiguration::IsolateConfiguration() = default; + +IsolateConfiguration::~IsolateConfiguration() = default; + +bool IsolateConfiguration::PrepareIsolate( + fml::WeakPtr isolate) { + if (!isolate) { + return false; + } + + if (isolate->GetPhase() != blink::DartIsolate::Phase::LibrariesSetup) { + FXL_DLOG(ERROR) + << "Isolate was in incorrect phase to be prepared for running."; + return false; + } + + return DoPrepareIsolate(*isolate); +} + +class PrecompiledIsolateConfiguration final : public IsolateConfiguration { + public: + PrecompiledIsolateConfiguration() = default; + + // |shell::IsolateConfiguration| + bool DoPrepareIsolate(blink::DartIsolate& isolate) override { + if (!blink::DartVM::IsRunningPrecompiledCode()) { + return false; + } + return isolate.PrepareForRunningFromPrecompiledCode(); + } + + private: + FXL_DISALLOW_COPY_AND_ASSIGN(PrecompiledIsolateConfiguration); +}; + +class SnapshotIsolateConfiguration : public IsolateConfiguration { + public: + SnapshotIsolateConfiguration(std::unique_ptr snapshot) + : snapshot_(std::move(snapshot)) {} + + // |shell::IsolateConfiguration| + bool DoPrepareIsolate(blink::DartIsolate& isolate) override { + if (blink::DartVM::IsRunningPrecompiledCode()) { + return false; + } + return isolate.PrepareForRunningFromSnapshot(std::move(snapshot_)); + } + + private: + std::unique_ptr snapshot_; + + FXL_DISALLOW_COPY_AND_ASSIGN(SnapshotIsolateConfiguration); +}; + +class SourceIsolateConfiguration final : public IsolateConfiguration { + public: + SourceIsolateConfiguration(std::string main_path, std::string packages_path) + : main_path_(std::move(main_path)), + packages_path_(std::move(packages_path)) {} + + // |shell::IsolateConfiguration| + bool DoPrepareIsolate(blink::DartIsolate& isolate) override { + if (blink::DartVM::IsRunningPrecompiledCode()) { + return false; + } + return isolate.PrepareForRunningFromSource(std::move(main_path_), + std::move(packages_path_)); + } + + private: + std::string main_path_; + std::string packages_path_; + + FXL_DISALLOW_COPY_AND_ASSIGN(SourceIsolateConfiguration); +}; + +std::unique_ptr IsolateConfiguration::InferFromSettings( + const blink::Settings& settings, + fxl::RefPtr asset_manager) { + // Running in AOT mode. + if (blink::DartVM::IsRunningPrecompiledCode()) { + return CreateForPrecompiledCode(); + } + + // Run from sources. + { + const auto& main = settings.main_dart_file_path; + const auto& packages = settings.packages_file_path; + if (main.size() != 0 && packages.size() != 0) { + return CreateForSource(std::move(main), std::move(packages)); + } + } + + // Running from kernel snapshot. + { + std::vector kernel; + if (asset_manager && asset_manager->GetAsBuffer( + settings.application_kernel_asset, &kernel)) { + return CreateForSnapshot( + std::make_unique(std::move(kernel))); + } + } + + // Running from script snapshot. + { + std::vector script_snapshot; + if (asset_manager && asset_manager->GetAsBuffer( + settings.script_snapshot_path, &script_snapshot)) { + return CreateForSnapshot( + std::make_unique(std::move(script_snapshot))); + } + } + + return nullptr; +} + +std::unique_ptr +IsolateConfiguration::CreateForPrecompiledCode() { + return std::make_unique(); +} + +std::unique_ptr IsolateConfiguration::CreateForSnapshot( + std::unique_ptr snapshot) { + return std::make_unique(std::move(snapshot)); +} + +std::unique_ptr IsolateConfiguration::CreateForSource( + std::string main_path, + std::string packages_path) { + return std::make_unique(std::move(main_path), + std::move(packages_path)); +} + +} // namespace shell diff --git a/shell/common/isolate_configuration.h b/shell/common/isolate_configuration.h new file mode 100644 index 0000000000000..82d06dac621b2 --- /dev/null +++ b/shell/common/isolate_configuration.h @@ -0,0 +1,51 @@ +// 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_SHELL_COMMON_ISOLATE_CONFIGURATION_H_ +#define FLUTTER_SHELL_COMMON_ISOLATE_CONFIGURATION_H_ + +#include +#include + +#include "flutter/assets/asset_manager.h" +#include "flutter/assets/asset_resolver.h" +#include "flutter/common/settings.h" +#include "flutter/fml/mapping.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/runtime/dart_isolate.h" +#include "lib/fxl/macros.h" + +namespace shell { + +class IsolateConfiguration { + public: + static std::unique_ptr InferFromSettings( + const blink::Settings& settings, + fxl::RefPtr asset_manager); + + static std::unique_ptr CreateForPrecompiledCode(); + + static std::unique_ptr CreateForSnapshot( + std::unique_ptr snapshot); + + static std::unique_ptr CreateForSource( + std::string main_path, + std::string packages_path); + + IsolateConfiguration(); + + virtual ~IsolateConfiguration(); + + bool PrepareIsolate(fml::WeakPtr isolate); + + protected: + virtual bool DoPrepareIsolate(blink::DartIsolate& isolate) = 0; + + private: + FXL_DISALLOW_COPY_AND_ASSIGN(IsolateConfiguration); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_COMMON_ISOLATE_CONFIGURATION_H_ diff --git a/shell/common/null_platform_view.cc b/shell/common/null_platform_view.cc deleted file mode 100644 index 49fdf5a935b80..0000000000000 --- a/shell/common/null_platform_view.cc +++ /dev/null @@ -1,37 +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. - -#include "flutter/shell/common/null_platform_view.h" - -#include "flutter/shell/common/null_rasterizer.h" -#include "flutter/shell/common/shell.h" - -namespace shell { - -NullPlatformView::NullPlatformView() - : PlatformView(std::make_unique()), weak_factory_(this) {} - -void NullPlatformView::Attach() { - CreateEngine(); -} - -NullPlatformView::~NullPlatformView() = default; - -fxl::WeakPtr NullPlatformView::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); -} - -bool NullPlatformView::ResourceContextMakeCurrent() { - return false; -} - -// Hot-reload of the null platform view is not supported. -void NullPlatformView::RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) {} - -void NullPlatformView::SetAssetBundlePath(const std::string& assets_directory) { -} - -} // namespace shell diff --git a/shell/common/null_platform_view.h b/shell/common/null_platform_view.h deleted file mode 100644 index eb23d67b48a7c..0000000000000 --- a/shell/common/null_platform_view.h +++ /dev/null @@ -1,39 +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 COMMON_NULL_PLATFORM_VIEW_H_ -#define COMMON_NULL_PLATFORM_VIEW_H_ - -#include "flutter/shell/common/platform_view.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" - -namespace shell { - -class NullPlatformView : public PlatformView { - public: - NullPlatformView(); - - ~NullPlatformView(); - - fxl::WeakPtr GetWeakPtr(); - - virtual void Attach() override; - - bool ResourceContextMakeCurrent() override; - - void RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) override; - void SetAssetBundlePath(const std::string& assets_directory) override; - - private: - fxl::WeakPtrFactory weak_factory_; - - FXL_DISALLOW_COPY_AND_ASSIGN(NullPlatformView); -}; - -} // namespace shell - -#endif // COMMON_NULL_PLATFORM_VIEW_H_ diff --git a/shell/common/null_rasterizer.cc b/shell/common/null_rasterizer.cc deleted file mode 100644 index 81efdd11d4970..0000000000000 --- a/shell/common/null_rasterizer.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/shell/common/null_rasterizer.h" - -namespace shell { - -NullRasterizer::NullRasterizer() : weak_factory_(this) {} - -void NullRasterizer::Setup( - std::unique_ptr surface_or_null, - fxl::Closure rasterizer_continuation, - fxl::AutoResetWaitableEvent* setup_completion_event) { - surface_ = std::move(surface_or_null); - rasterizer_continuation(); - setup_completion_event->Signal(); -} - -void NullRasterizer::Teardown( - fxl::AutoResetWaitableEvent* teardown_completion_event) { - if (surface_) { - surface_.reset(); - } - teardown_completion_event->Signal(); -} - -fml::WeakPtr NullRasterizer::GetWeakRasterizerPtr() { - return weak_factory_.GetWeakPtr(); -} - -flow::LayerTree* NullRasterizer::GetLastLayerTree() { - return nullptr; -} - -void NullRasterizer::DrawLastLayerTree() { - // Null rasterizer. Nothing to do. -} - -flow::TextureRegistry& NullRasterizer::GetTextureRegistry() { - return *texture_registry_; -} - -void NullRasterizer::Clear(SkColor color, const SkISize& size) { - // Null rasterizer. Nothing to do. -} - -void NullRasterizer::Draw( - fxl::RefPtr> pipeline) { - FXL_ALLOW_UNUSED_LOCAL( - pipeline->Consume([](std::unique_ptr) { - // Drop the layer tree on the floor. We only need the pipeline empty so - // that frame requests are not deferred indefinitely due to - // backpressure. - })); -} - -void NullRasterizer::AddNextFrameCallback(fxl::Closure nextFrameCallback) { - // Null rasterizer. Nothing to do. -} - -void NullRasterizer::SetTextureRegistry( - flow::TextureRegistry* textureRegistry) { - texture_registry_ = textureRegistry; -} - -} // namespace shell diff --git a/shell/common/null_rasterizer.h b/shell/common/null_rasterizer.h deleted file mode 100644 index 8558a3c3accaa..0000000000000 --- a/shell/common/null_rasterizer.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2016 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_SHELL_COMMON_NULL_RASTERIZER_H_ -#define FLUTTER_SHELL_COMMON_NULL_RASTERIZER_H_ - -#include "flutter/shell/common/rasterizer.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" - -namespace shell { - -class NullRasterizer : public Rasterizer { - public: - NullRasterizer(); - - void Setup(std::unique_ptr surface_or_null, - fxl::Closure rasterizer_continuation, - fxl::AutoResetWaitableEvent* setup_completion_event) override; - - void Teardown( - fxl::AutoResetWaitableEvent* teardown_completion_event) override; - - void Clear(SkColor color, const SkISize& size) override; - - fml::WeakPtr GetWeakRasterizerPtr() override; - - flow::LayerTree* GetLastLayerTree() override; - - void DrawLastLayerTree() override; - - flow::TextureRegistry& GetTextureRegistry() override; - - void Draw(fxl::RefPtr> pipeline) override; - - void AddNextFrameCallback(fxl::Closure nextFrameCallback) override; - - void SetTextureRegistry(flow::TextureRegistry* textureRegistry) override; - - private: - std::unique_ptr surface_; - fml::WeakPtrFactory weak_factory_; - flow::TextureRegistry* texture_registry_; - - FXL_DISALLOW_COPY_AND_ASSIGN(NullRasterizer); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_COMMON_NULL_RASTERIZER_H_ diff --git a/shell/common/platform_view.cc b/shell/common/platform_view.cc index 2d5715a1733bd..b2bfce051a5bf 100644 --- a/shell/common/platform_view.cc +++ b/shell/common/platform_view.cc @@ -6,124 +6,74 @@ #include -#include "flutter/common/threads.h" -#include "flutter/lib/ui/painting/resource_context.h" #include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/shell.h" #include "flutter/shell/common/vsync_waiter_fallback.h" #include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/synchronization/waitable_event.h" #include "third_party/skia/include/gpu/GrContextOptions.h" #include "third_party/skia/include/gpu/gl/GrGLInterface.h" namespace shell { -PlatformView::PlatformView(std::unique_ptr rasterizer) - : rasterizer_(std::move(rasterizer)), size_(SkISize::Make(0, 0)) { - rasterizer_->SetTextureRegistry(&texture_registry_); - Shell::Shared().AddPlatformView(this); +PlatformView::PlatformView(Delegate& delegate, blink::TaskRunners task_runners) + : delegate_(delegate), + task_runners_(std::move(task_runners)), + size_(SkISize::Make(0, 0)), + weak_factory_(this) { + weak_prototype_ = weak_factory_.GetWeakPtr(); } -PlatformView::~PlatformView() { - Shell::Shared().RemovePlatformView(this); +PlatformView::~PlatformView() = default; - Rasterizer* rasterizer = rasterizer_.release(); - blink::Threads::Gpu()->PostTask([rasterizer]() { delete rasterizer; }); - - Engine* engine = engine_.release(); - blink::Threads::UI()->PostTask([engine]() { delete engine; }); -} - -void PlatformView::SetRasterizer(std::unique_ptr rasterizer) { - Rasterizer* r = rasterizer_.release(); - blink::Threads::Gpu()->PostTask([r]() { delete r; }); - rasterizer_ = std::move(rasterizer); - rasterizer_->SetTextureRegistry(&texture_registry_); - engine_->set_rasterizer(rasterizer_->GetWeakRasterizerPtr()); -} - -void PlatformView::CreateEngine() { - engine_.reset(new Engine(this)); +std::unique_ptr PlatformView::CreateVSyncWaiter() { + FXL_DLOG(WARNING) + << "This platform does not provide a Vsync waiter implementation. A " + "simple timer based fallback is being used."; + return std::make_unique(task_runners_); } void PlatformView::DispatchPlatformMessage( fxl::RefPtr message) { - blink::Threads::UI()->PostTask( - [engine = engine_->GetWeakPtr(), message = std::move(message)] { - if (engine) { - engine->DispatchPlatformMessage(message); - } - }); + delegate_.OnPlatformViewDispatchPlatformMessage(*this, std::move(message)); +} + +void PlatformView::DispatchPointerDataPacket( + std::unique_ptr packet) { + delegate_.OnPlatformViewDispatchPointerDataPacket(*this, std::move(packet)); } void PlatformView::DispatchSemanticsAction(int32_t id, blink::SemanticsAction action, std::vector args) { - blink::Threads::UI()->PostTask( - [engine = engine_->GetWeakPtr(), id, action, args = std::move(args)] { - if (engine) { - engine->DispatchSemanticsAction( - id, static_cast(action), std::move(args)); - } - }); + delegate_.OnPlatformViewDispatchSemanticsAction(*this, id, action, + std::move(args)); } void PlatformView::SetSemanticsEnabled(bool enabled) { - blink::Threads::UI()->PostTask([engine = engine_->GetWeakPtr(), enabled] { - if (engine) - engine->SetSemanticsEnabled(enabled); - }); + delegate_.OnPlatformViewSetSemanticsEnabled(*this, enabled); } -void PlatformView::NotifyCreated(std::unique_ptr surface) { - NotifyCreated(std::move(surface), []() {}); +void PlatformView::SetViewportMetrics(const blink::ViewportMetrics& metrics) { + delegate_.OnPlatformViewSetViewportMetrics(*this, metrics); } -void PlatformView::NotifyCreated(std::unique_ptr surface, - fxl::Closure caller_continuation) { - fxl::AutoResetWaitableEvent latch; - - auto ui_continuation = fxl::MakeCopyable([this, // - surface = std::move(surface), // - caller_continuation, // - &latch]() mutable { - auto gpu_continuation = fxl::MakeCopyable([this, // - surface = std::move(surface), // - caller_continuation, // - &latch]() mutable { - // Runs on the GPU Thread. So does the Caller Continuation. - rasterizer_->Setup(std::move(surface), caller_continuation, &latch); - }); - // Runs on the UI Thread. - engine_->OnOutputSurfaceCreated(std::move(gpu_continuation)); - }); - - // Runs on the Platform Thread. - blink::Threads::UI()->PostTask(std::move(ui_continuation)); - - latch.Wait(); +void PlatformView::NotifyCreated() { + delegate_.OnPlatformViewCreated(*this, CreateRenderingSurface()); } void PlatformView::NotifyDestroyed() { - fxl::AutoResetWaitableEvent latch; - - auto engine_continuation = [this, &latch]() { - rasterizer_->Teardown(&latch); - }; - - blink::Threads::UI()->PostTask([this, engine_continuation]() { - engine_->OnOutputSurfaceDestroyed(engine_continuation); - }); - - latch.Wait(); + delegate_.OnPlatformViewDestroyed(*this); } -std::weak_ptr PlatformView::GetWeakPtr() { - return shared_from_this(); +sk_sp PlatformView::CreateResourceContext() const { + FXL_DLOG(WARNING) << "This platform does not setup the resource " + "context on the IO thread for async texture uploads."; + return nullptr; } -VsyncWaiter* PlatformView::GetVsyncWaiter() { - if (!vsync_waiter_) - vsync_waiter_ = std::make_unique(); - return vsync_waiter_.get(); +fml::WeakPtr PlatformView::GetWeakPtr() const { + return weak_prototype_; } void PlatformView::UpdateSemantics(blink::SemanticsNodeUpdates update) {} @@ -135,71 +85,31 @@ void PlatformView::HandlePlatformMessage( } void PlatformView::RegisterTexture(std::shared_ptr texture) { - ASSERT_IS_PLATFORM_THREAD - blink::Threads::Gpu()->PostTask([this, texture]() { - rasterizer_->GetTextureRegistry().RegisterTexture(texture); - }); + delegate_.OnPlatformViewRegisterTexture(*this, std::move(texture)); } void PlatformView::UnregisterTexture(int64_t texture_id) { - ASSERT_IS_PLATFORM_THREAD - blink::Threads::Gpu()->PostTask([this, texture_id]() { - rasterizer_->GetTextureRegistry().UnregisterTexture(texture_id); - }); + delegate_.OnPlatformViewUnregisterTexture(*this, texture_id); } void PlatformView::MarkTextureFrameAvailable(int64_t texture_id) { - ASSERT_IS_PLATFORM_THREAD - blink::Threads::UI()->PostTask([this]() { engine_->ScheduleFrame(false); }); + delegate_.OnPlatformViewMarkTextureFrameAvailable(*this, texture_id); } -void PlatformView::SetupResourceContextOnIOThread() { - fxl::AutoResetWaitableEvent latch; - - blink::Threads::IO()->PostTask( - [this, &latch]() { SetupResourceContextOnIOThreadPerform(&latch); }); - - latch.Wait(); +std::unique_ptr PlatformView::CreateRenderingSurface() { + // We have a default implementation because tests create a platform view but + // never a rendering surface. + FXL_DCHECK(false) << "This platform does not provide a rendering surface but " + "it was notified of surface rendering surface creation."; + return nullptr; } -void PlatformView::SetupResourceContextOnIOThreadPerform( - fxl::AutoResetWaitableEvent* latch) { - std::unique_ptr resourceContext = - blink::ResourceContext::Acquire(); - if (resourceContext->Get() != nullptr) { - // The resource context was already setup. This could happen if platforms - // try to setup a context multiple times, or, if there are multiple platform - // views. In any case, there is nothing else to do. So just signal the - // latch. - latch->Signal(); +void PlatformView::SetNextFrameCallback(fxl::Closure closure) { + if (!closure) { return; } - bool current = ResourceContextMakeCurrent(); - - if (!current) { - FXL_DLOG(WARNING) - << "WARNING: Could not setup a context on the resource loader."; - latch->Signal(); - return; - } - - GrContextOptions options; - // There is currently a bug with doing GPU YUV to RGB conversions on the IO - // thread. The necessary work isn't being flushed or synchronized with the - // other threads correctly, so the textures end up blank. For now, suppress - // that feature, which will cause texture uploads to do CPU YUV conversion. - options.fDisableGpuYUVConversion = true; - - blink::ResourceContext::Set( - GrContext::MakeGL(GrGLMakeNativeInterface(), options)); - - // Do not cache textures created by the image decoder. These textures should - // be deleted when they are no longer referenced by an SkImage. - if (resourceContext->Get()) - resourceContext->Get()->setResourceCacheLimits(0, 0); - - latch->Signal(); + delegate_.OnPlatformViewSetNextFrameCallback(*this, std::move(closure)); } } // namespace shell diff --git a/shell/common/platform_view.h b/shell/common/platform_view.h index 66b1fcae10c79..56179a6114777 100644 --- a/shell/common/platform_view.h +++ b/shell/common/platform_view.h @@ -7,63 +7,104 @@ #include +#include "flutter/common/task_runners.h" #include "flutter/flow/texture.h" +#include "flutter/fml/memory/weak_ptr.h" #include "flutter/lib/ui/semantics/semantics_node.h" -#include "flutter/shell/common/engine.h" -#include "flutter/shell/common/shell.h" +#include "flutter/lib/ui/window/platform_message.h" +#include "flutter/lib/ui/window/pointer_data_packet.h" +#include "flutter/lib/ui/window/viewport_metrics.h" #include "flutter/shell/common/surface.h" #include "flutter/shell/common/vsync_waiter.h" #include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" -#include "lib/fxl/synchronization/waitable_event.h" #include "third_party/skia/include/core/SkSize.h" #include "third_party/skia/include/gpu/GrContext.h" namespace shell { -class Rasterizer; +class Shell; -class PlatformView : public std::enable_shared_from_this { +class PlatformView { public: - struct SurfaceConfig { - uint8_t red_bits = 8; - uint8_t green_bits = 8; - uint8_t blue_bits = 8; - uint8_t alpha_bits = 8; - uint8_t depth_bits = 0; - uint8_t stencil_bits = 0; + class Delegate { + public: + virtual void OnPlatformViewCreated(const PlatformView& view, + std::unique_ptr surface) = 0; + + virtual void OnPlatformViewDestroyed(const PlatformView& view) = 0; + + virtual void OnPlatformViewSetNextFrameCallback(const PlatformView& view, + fxl::Closure closure) = 0; + + virtual void OnPlatformViewSetViewportMetrics( + const PlatformView& view, + const blink::ViewportMetrics& metrics) = 0; + + virtual void OnPlatformViewDispatchPlatformMessage( + const PlatformView& view, + fxl::RefPtr message) = 0; + + virtual void OnPlatformViewDispatchPointerDataPacket( + const PlatformView& view, + std::unique_ptr packet) = 0; + + virtual void OnPlatformViewDispatchSemanticsAction( + const PlatformView& view, + int32_t id, + blink::SemanticsAction action, + std::vector args) = 0; + + virtual void OnPlatformViewSetSemanticsEnabled(const PlatformView& view, + bool enabled) = 0; + + virtual void OnPlatformViewRegisterTexture( + const PlatformView& view, + std::shared_ptr texture) = 0; + + virtual void OnPlatformViewUnregisterTexture(const PlatformView& view, + int64_t texture_id) = 0; + + virtual void OnPlatformViewMarkTextureFrameAvailable( + const PlatformView& view, + int64_t texture_id) = 0; }; - void SetupResourceContextOnIOThread(); + explicit PlatformView(Delegate& delegate, blink::TaskRunners task_runners); virtual ~PlatformView(); - virtual void Attach() = 0; + virtual std::unique_ptr CreateVSyncWaiter(); void DispatchPlatformMessage(fxl::RefPtr message); + void DispatchSemanticsAction(int32_t id, blink::SemanticsAction action, std::vector args); - void SetSemanticsEnabled(bool enabled); - void NotifyCreated(std::unique_ptr surface); + virtual void SetSemanticsEnabled(bool enabled); - void NotifyCreated(std::unique_ptr surface, - fxl::Closure continuation); + void SetViewportMetrics(const blink::ViewportMetrics& metrics); - void NotifyDestroyed(); + void NotifyCreated(); - std::weak_ptr GetWeakPtr(); + virtual void NotifyDestroyed(); - // The VsyncWaiter will live at least as long as the PlatformView. - virtual VsyncWaiter* GetVsyncWaiter(); + // Unlike all other methods on the platform view, this one may be called on a + // non-platform task runner. + virtual sk_sp CreateResourceContext() const; - virtual bool ResourceContextMakeCurrent() = 0; + fml::WeakPtr GetWeakPtr() const; virtual void UpdateSemantics(blink::SemanticsNodeUpdates update); + virtual void HandlePlatformMessage( fxl::RefPtr message); + void SetNextFrameCallback(fxl::Closure closure); + + void DispatchPointerDataPacket( + std::unique_ptr packet); + // Called once per texture, on the platform thread. void RegisterTexture(std::shared_ptr texture); @@ -71,34 +112,18 @@ class PlatformView : public std::enable_shared_from_this { void UnregisterTexture(int64_t texture_id); // Called once per texture update (e.g. video frame), on the platform thread. - virtual void MarkTextureFrameAvailable(int64_t texture_id); - - void SetRasterizer(std::unique_ptr rasterizer); - - Rasterizer& rasterizer() { return *rasterizer_; } - Engine& engine() { return *engine_; } - - virtual void RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) = 0; - - virtual void SetAssetBundlePath(const std::string& assets_directory) = 0; + void MarkTextureFrameAvailable(int64_t texture_id); protected: - explicit PlatformView(std::unique_ptr rasterizer); - - void CreateEngine(); - - void SetupResourceContextOnIOThreadPerform( - fxl::AutoResetWaitableEvent* event); - - SurfaceConfig surface_config_; - std::unique_ptr rasterizer_; - flow::TextureRegistry texture_registry_; - std::unique_ptr engine_; + PlatformView::Delegate& delegate_; + const blink::TaskRunners task_runners_; std::unique_ptr vsync_waiter_; SkISize size_; + fml::WeakPtr weak_prototype_; + fml::WeakPtrFactory weak_factory_; + + virtual std::unique_ptr CreateRenderingSurface(); private: FXL_DISALLOW_COPY_AND_ASSIGN(PlatformView); diff --git a/shell/common/platform_view_service_protocol.cc b/shell/common/platform_view_service_protocol.cc deleted file mode 100644 index 8785c4812e202..0000000000000 --- a/shell/common/platform_view_service_protocol.cc +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/shell/common/platform_view_service_protocol.h" - -#include - -#include -#include - -#include "flutter/common/threads.h" -#include "flutter/shell/common/picture_serializer.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/shell.h" -#include "lib/fxl/memory/weak_ptr.h" -#include "third_party/skia/include/core/SkSurface.h" -#include "third_party/skia/src/utils/SkBase64.h" - -namespace shell { -namespace { - -constexpr char kViewIdPrefx[] = "_flutterView/"; -constexpr size_t kViewIdPrefxLength = sizeof(kViewIdPrefx) - 1; - -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; -} - -static bool ErrorServer(const char** json_object, const char* message) { - const intptr_t kServerError = -32000; - std::stringstream response; - response << "{\"code\":" << std::to_string(kServerError) << ","; - response << "\"message\":\"" << message << "\"}"; - *json_object = strdup(response.str().c_str()); - return false; -} - -static void AppendIsolateRef(std::stringstream* stream, - int64_t main_port, - const std::string name) { - *stream << "{\"type\":\"@Isolate\",\"fixedId\":true,\"id\":\"isolates/"; - *stream << main_port << "\",\"name\":\"" << name << "\","; - *stream << "\"number\":\"" << main_port << "\"}"; -} - -static void AppendFlutterView(std::stringstream* stream, - uintptr_t view_id, - int64_t isolate_id, - const std::string isolate_name) { - *stream << "{\"type\":\"FlutterView\", \"id\": \"" << kViewIdPrefx << "0x" - << std::hex << view_id << std::dec << "\""; - if (isolate_id != ILLEGAL_PORT) { - // Append the isolate (if it exists). - *stream << "," - << "\"isolate\":"; - AppendIsolateRef(stream, isolate_id, isolate_name); - } - *stream << "}"; -} - -} // namespace - -void PlatformViewServiceProtocol::RegisterHook(bool running_precompiled_code) { - // Listing of FlutterViews. - Dart_RegisterRootServiceRequestCallback(kListViewsExtensionName, &ListViews, - nullptr); - // Screenshot. - Dart_RegisterRootServiceRequestCallback(kScreenshotExtensionName, &Screenshot, - nullptr); - - // SkPicture Screenshot. - Dart_RegisterRootServiceRequestCallback(kScreenshotSkpExtensionName, - &ScreenshotSkp, nullptr); - - // The following set of service protocol extensions require debug build - if (running_precompiled_code) { - return; - } - Dart_RegisterRootServiceRequestCallback(kRunInViewExtensionName, &RunInView, - nullptr); - Dart_RegisterRootServiceRequestCallback(kSetAssetBundlePathExtensionName, - &SetAssetBundlePath, nullptr); - // [benchmark helper] Wait for the UI Thread to idle. - Dart_RegisterRootServiceRequestCallback(kFlushUIThreadTasksExtensionName, - &FlushUIThreadTasks, nullptr); -} - -const char* PlatformViewServiceProtocol::kRunInViewExtensionName = - "_flutter.runInView"; - -bool PlatformViewServiceProtocol::RunInView(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - 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 (strncmp(view_id, kViewIdPrefx, kViewIdPrefxLength) != 0) { - 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 + kViewIdPrefxLength), 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; - Dart_Port main_port = ILLEGAL_PORT; - std::string isolate_name; - shell.RunInPlatformView(view_id_as_num, main_script, packages_file, - asset_directory, &view_existed, &main_port, - &isolate_name); - - if (!view_existed) { - // If the view did not exist this request has definitely failed. - return ErrorUnknownView(json_object, view_id); - } - - // The view existed and the isolate was created. Success. - std::stringstream response; - response << "{\"type\":\"Success\"," - << "\"view\":"; - AppendFlutterView(&response, view_id_as_num, main_port, isolate_name); - response << "}"; - *json_object = strdup(response.str().c_str()); - return true; -} - -const char* PlatformViewServiceProtocol::kListViewsExtensionName = - "_flutter.listViews"; - -bool PlatformViewServiceProtocol::ListViews(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - std::stringstream response; - response << "{\"type\":\"FlutterViewList\",\"views\":["; - bool prefix_comma = false; - Shell::Shared().IteratePlatformViews( - [&response, &prefix_comma](PlatformView* view) -> bool { - if (prefix_comma) { - response << ','; - } else { - prefix_comma = true; - } - AppendFlutterView(&response, reinterpret_cast(view), - view->engine().GetUIIsolateMainPort(), - view->engine().GetUIIsolateName()); - return true; - }); - response << "]}"; - // Copy the response. - *json_object = strdup(response.str().c_str()); - return true; -} - -const char* PlatformViewServiceProtocol::kScreenshotExtensionName = - "_flutter.screenshot"; - -static sk_sp EncodeBitmapAsPNG(const SkBitmap& bitmap) { - return SkEncodeBitmap(bitmap, SkEncodedImageFormat::kPNG, 100); -} - -static fml::WeakPtr GetRandomRasterizer() { - fml::WeakPtr rasterizer; - Shell::Shared().IteratePlatformViews( - [&rasterizer](PlatformView* view) -> bool { - rasterizer = view->rasterizer().GetWeakRasterizerPtr(); - // We just grab the first rasterizer so there is no need to iterate - // further. - return false; - }); - return rasterizer; -} - -bool PlatformViewServiceProtocol::Screenshot(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - fxl::AutoResetWaitableEvent latch; - SkBitmap bitmap; - blink::Threads::Gpu()->PostTask([&latch, &bitmap]() { - ScreenshotGpuTask(&bitmap); - latch.Signal(); - }); - - latch.Wait(); - - sk_sp png(EncodeBitmapAsPNG(bitmap)); - - if (!png) - return ErrorServer(json_object, "can not encode screenshot"); - - size_t b64_size = SkBase64::Encode(png->data(), png->size(), nullptr); - SkAutoTMalloc b64_data(b64_size); - SkBase64::Encode(png->data(), png->size(), b64_data.get()); - - std::stringstream response; - response << "{\"type\":\"Screenshot\"," - << "\"screenshot\":\"" << std::string{b64_data.get(), b64_size} - << "\"}"; - *json_object = strdup(response.str().c_str()); - return true; -} - -void PlatformViewServiceProtocol::ScreenshotGpuTask(SkBitmap* bitmap) { - auto rasterizer = GetRandomRasterizer(); - - if (!rasterizer) - return; - - flow::LayerTree* layer_tree = rasterizer->GetLastLayerTree(); - if (layer_tree == nullptr) - return; - - const SkISize& frame_size = layer_tree->frame_size(); - if (!bitmap->tryAllocN32Pixels(frame_size.width(), frame_size.height())) - return; - - sk_sp surface = SkSurface::MakeRasterDirect( - bitmap->info(), bitmap->getPixels(), bitmap->rowBytes()); - - flow::CompositorContext compositor_context(nullptr); - SkCanvas* canvas = surface->getCanvas(); - flow::CompositorContext::ScopedFrame frame = - compositor_context.AcquireFrame(nullptr, canvas, false); - - canvas->clear(SK_ColorBLACK); - layer_tree->Raster(frame); - canvas->flush(); -} - -const char* PlatformViewServiceProtocol::kScreenshotSkpExtensionName = - "_flutter.screenshotSkp"; - -bool PlatformViewServiceProtocol::ScreenshotSkp(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - fxl::AutoResetWaitableEvent latch; - sk_sp picture; - blink::Threads::Gpu()->PostTask([&latch, &picture]() { - picture = ScreenshotSkpGpuTask(); - latch.Signal(); - }); - - latch.Wait(); - - sk_sp skp_data = picture->serialize(); - - size_t b64_size = - SkBase64::Encode(skp_data->data(), skp_data->size(), nullptr); - SkAutoTMalloc b64_data(b64_size); - SkBase64::Encode(skp_data->data(), skp_data->size(), b64_data.get()); - - std::stringstream response; - response << "{\"type\":\"ScreenshotSkp\"," - << "\"skp\":\"" << std::string{b64_data.get(), b64_size} << "\"}"; - *json_object = strdup(response.str().c_str()); - return true; -} - -sk_sp PlatformViewServiceProtocol::ScreenshotSkpGpuTask() { - auto rasterizer = GetRandomRasterizer(); - - if (!rasterizer) - return nullptr; - - flow::LayerTree* layer_tree = rasterizer->GetLastLayerTree(); - if (layer_tree == nullptr) - return nullptr; - - SkPictureRecorder recorder; - recorder.beginRecording(SkRect::MakeWH(layer_tree->frame_size().width(), - layer_tree->frame_size().height())); - - flow::CompositorContext compositor_context(nullptr); - flow::CompositorContext::ScopedFrame frame = compositor_context.AcquireFrame( - nullptr, recorder.getRecordingCanvas(), false); - layer_tree->Raster(frame); - - return recorder.finishRecordingAsPicture(); -} - -const char* PlatformViewServiceProtocol::kFlushUIThreadTasksExtensionName = - "_flutter.flushUIThreadTasks"; - -// This API should not be invoked by production code. -// It can potentially starve the service isolate if the main isolate pauses -// at a breakpoint or is in an infinite loop. -// -// It should be invoked from the VM Service and and blocks it until UI thread -// tasks are processed. -bool PlatformViewServiceProtocol::FlushUIThreadTasks(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - fxl::AutoResetWaitableEvent latch; - blink::Threads::UI()->PostTask([&latch]() { - // This task is empty because we just need to synchronize this RPC with the - // UI Thread - latch.Signal(); - }); - - latch.Wait(); - - *json_object = strdup("{\"type\":\"Success\"}"); - return true; -} - -const char* PlatformViewServiceProtocol::kSetAssetBundlePathExtensionName = - "_flutter.setAssetBundlePath"; - -bool PlatformViewServiceProtocol::SetAssetBundlePath(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - const char* view_id = - ValueForKey(param_keys, param_values, num_params, "viewId"); - if (view_id == nullptr) { - return ErrorMissingParameter(json_object, "viewId"); - } - if (strncmp(view_id, kViewIdPrefx, kViewIdPrefxLength) != 0) { - return ErrorBadParameter(json_object, "viewId", view_id); - } - const char* asset_directory = - ValueForKey(param_keys, param_values, num_params, "assetDirectory"); - if (asset_directory == nullptr) { - return ErrorMissingParameter(json_object, "assetDirectory"); - } - - // Convert the actual flutter view hex id into a number. - uintptr_t view_id_as_num = - std::stoull((view_id + kViewIdPrefxLength), nullptr, 16); - - // Ask the Shell to update asset bundle path in the specified view. - // This will run a task on the UI thread before returning. - Shell& shell = Shell::Shared(); - bool view_existed = false; - Dart_Port main_port = ILLEGAL_PORT; - std::string isolate_name; - shell.SetAssetBundlePathInPlatformView(view_id_as_num, asset_directory, - &view_existed, &main_port, - &isolate_name); - - if (!view_existed) { - // If the view did not exist this request has definitely failed. - return ErrorUnknownView(json_object, view_id); - } - - // The view existed and the isolate was created. Success. - std::stringstream response; - response << "{\"type\":\"Success\"," - << "\"view\":"; - AppendFlutterView(&response, view_id_as_num, main_port, isolate_name); - response << "}"; - *json_object = strdup(response.str().c_str()); - return true; -} - -} // namespace shell diff --git a/shell/common/platform_view_service_protocol.h b/shell/common/platform_view_service_protocol.h deleted file mode 100644 index b7f74b56a08ba..0000000000000 --- a/shell/common/platform_view_service_protocol.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2016 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 SHELL_COMMON_VIEW_SERVICE_PROTOCOL_H_ -#define SHELL_COMMON_VIEW_SERVICE_PROTOCOL_H_ - -#include - -#include "flutter/shell/common/platform_view.h" -#include "lib/fxl/synchronization/waitable_event.h" -#include "third_party/dart/runtime/include/dart_tools_api.h" -#include "third_party/skia/include/core/SkBitmap.h" - -namespace shell { - -class PlatformViewServiceProtocol { - public: - static void RegisterHook(bool running_precompiled_code); - - private: - static const char* kRunInViewExtensionName; - // It should be invoked from the VM Service and and blocks it until previous - // UI thread tasks are processed. - static bool RunInView(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); - - static const char* kListViewsExtensionName; - static bool ListViews(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); - - static const char* kScreenshotExtensionName; - // It should be invoked from the VM Service and and blocks it until previous - // GPU thread tasks are processed. - static bool Screenshot(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); - static void ScreenshotGpuTask(SkBitmap* bitmap); - - static const char* kScreenshotSkpExtensionName; - static bool ScreenshotSkp(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); - static sk_sp ScreenshotSkpGpuTask(); - - // This API should not be invoked by production code. - // It can potentially starve the service isolate if the main isolate pauses - // at a breakpoint or is in an infinite loop. - // - // It should be invoked from the VM Service and and blocks it until previous - // GPU thread tasks are processed. - static const char* kFlushUIThreadTasksExtensionName; - static bool FlushUIThreadTasks(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); - - static const char* kSetAssetBundlePathExtensionName; - static bool SetAssetBundlePath(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); -}; - -} // namespace shell - -#endif // SHELL_COMMON_VIEW_SERVICE_PROTOCOL_H_ diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 905ee6285c5d3..5a519b3efea26 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -4,8 +4,205 @@ #include "flutter/shell/common/rasterizer.h" +#include + +#include "third_party/skia/include/core/SkEncodedImageFormat.h" +#include "third_party/skia/include/core/SkImageEncoder.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/src/utils/SkBase64.h" + namespace shell { +Rasterizer::Rasterizer(blink::TaskRunners task_runners) + : task_runners_(std::move(task_runners)), weak_factory_(this) { + weak_prototype_ = weak_factory_.GetWeakPtr(); +} + Rasterizer::~Rasterizer() = default; +fml::WeakPtr Rasterizer::GetWeakPtr() const { + return weak_prototype_; +} + +void Rasterizer::Setup(std::unique_ptr surface) { + surface_ = std::move(surface); +} + +void Rasterizer::Teardown() { + surface_.reset(); + last_layer_tree_.reset(); +} + +flow::TextureRegistry* Rasterizer::GetTextureRegistry() { + if (!surface_) { + return nullptr; + } + + return &(surface_->GetCompositorContext().texture_registry()); +} + +flow::LayerTree* Rasterizer::GetLastLayerTree() { + return last_layer_tree_.get(); +} + +void Rasterizer::DrawLastLayerTree() { + if (!last_layer_tree_ || !surface_) { + return; + } + DrawToSurface(*last_layer_tree_); +} + +void Rasterizer::Draw( + fxl::RefPtr> pipeline) { + TRACE_EVENT0("flutter", "GPURasterizer::Draw"); + + flutter::Pipeline::Consumer consumer = + std::bind(&Rasterizer::DoDraw, this, std::placeholders::_1); + + // Consume as many pipeline items as possible. But yield the event loop + // between successive tries. + switch (pipeline->Consume(consumer)) { + case flutter::PipelineConsumeResult::MoreAvailable: { + task_runners_.GetGPUTaskRunner()->PostTask( + [weak_this = weak_factory_.GetWeakPtr(), pipeline]() { + if (weak_this) { + weak_this->Draw(pipeline); + } + }); + break; + } + default: + break; + } +} + +void Rasterizer::DoDraw(std::unique_ptr layer_tree) { + if (!layer_tree || !surface_) { + return; + } + + if (DrawToSurface(*layer_tree)) { + last_layer_tree_ = std::move(layer_tree); + } +} + +bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) { + FXL_DCHECK(surface_); + + auto frame = surface_->AcquireFrame(layer_tree.frame_size()); + + if (frame == nullptr) { + return false; + } + + auto& compositor_context = surface_->GetCompositorContext(); + + // There is no way for the compositor to know how long the layer tree + // construction took. Fortunately, the layer tree does. Grab that time + // for instrumentation. + compositor_context.engine_time().SetLapTime(layer_tree.construction_time()); + + auto compositor_frame = compositor_context.AcquireFrame( + surface_->GetContext(), frame->SkiaCanvas(), true); + + if (compositor_frame && compositor_frame->Raster(layer_tree, false)) { + frame->Submit(); + FireNextFrameCallbackIfPresent(); + return true; + } + + return false; +} + +static sk_sp ScreenshotLayerTreeAsPicture(flow::LayerTree* tree) { + FXL_DCHECK(tree != nullptr); + SkPictureRecorder recorder; + recorder.beginRecording( + SkRect::MakeWH(tree->frame_size().width(), tree->frame_size().height())); + + flow::CompositorContext compositor_context; + auto frame = compositor_context.AcquireFrame( + nullptr, recorder.getRecordingCanvas(), false); + + frame->Raster(*tree, true); + + return recorder.finishRecordingAsPicture(); +} + +static sk_sp ScreenshotLayerTreeAsImage(flow::LayerTree* tree, + bool compressed) { + const SkISize& frame_size = tree->frame_size(); + SkBitmap bitmap; + if (!bitmap.tryAllocN32Pixels(frame_size.width(), frame_size.height())) { + return nullptr; + } + auto bitmap_surface = SkSurface::MakeRasterDirect( + bitmap.info(), bitmap.getPixels(), bitmap.rowBytes()); + flow::CompositorContext compositor_context; + auto canvas = bitmap_surface->getCanvas(); + auto frame = compositor_context.AcquireFrame(nullptr, canvas, false); + canvas->clear(SK_ColorBLACK); + frame->Raster(*tree, true); + canvas->flush(); + if (compressed) { + return SkEncodeBitmap(bitmap, SkEncodedImageFormat::kPNG, 100); + } else { + return SkData::MakeWithCopy(bitmap.getPixels(), bitmap.computeByteSize()); + } + return nullptr; +} + +Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree( + Rasterizer::ScreenshotType type, + bool base64_encode) { + auto layer_tree = GetLastLayerTree(); + if (layer_tree == nullptr) { + FXL_DLOG(INFO) << "Last layer tree was null when screenshotting."; + return {}; + } + + sk_sp data = nullptr; + + switch (type) { + case ScreenshotType::SkiaPicture: + data = ScreenshotLayerTreeAsPicture(layer_tree)->serialize(); + break; + case ScreenshotType::UncompressedImage: + data = ScreenshotLayerTreeAsImage(layer_tree, false); + break; + case ScreenshotType::CompressedImage: + data = ScreenshotLayerTreeAsImage(layer_tree, true); + break; + } + + if (data == nullptr) { + FXL_DLOG(INFO) << "Sceenshot data was null."; + return {}; + } + + if (base64_encode) { + size_t b64_size = SkBase64::Encode(data->data(), data->size(), nullptr); + auto b64_data = SkData::MakeUninitialized(b64_size); + SkBase64::Encode(data->data(), data->size(), b64_data->writable_data()); + return Rasterizer::Screenshot{b64_data, layer_tree->frame_size()}; + } + + return Rasterizer::Screenshot{data, layer_tree->frame_size()}; +} + +void Rasterizer::SetNextFrameCallback(fxl::Closure callback) { + next_frame_callback_ = callback; +} + +void Rasterizer::FireNextFrameCallbackIfPresent() { + if (!next_frame_callback_) { + return; + } + // It is safe for the callback to set a new callback. + auto callback = next_frame_callback_; + next_frame_callback_ = nullptr; + callback(); +} + } // namespace shell diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 6f45f49d8178a..908717b74c168 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -7,6 +7,7 @@ #include +#include "flutter/common/task_runners.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/surface.h" @@ -16,34 +17,64 @@ namespace shell { -class Rasterizer { +class Rasterizer final { public: - virtual ~Rasterizer(); + Rasterizer(blink::TaskRunners task_runners); - virtual void Setup(std::unique_ptr surface_or_null, - fxl::Closure rasterizer_continuation, - fxl::AutoResetWaitableEvent* setup_completion_event) = 0; + ~Rasterizer(); - virtual void Teardown( - fxl::AutoResetWaitableEvent* teardown_completion_event) = 0; + void Setup(std::unique_ptr surface); - virtual void Clear(SkColor color, const SkISize& size) = 0; + void Teardown(); - virtual fml::WeakPtr GetWeakRasterizerPtr() = 0; + fml::WeakPtr GetWeakPtr() const; - virtual flow::LayerTree* GetLastLayerTree() = 0; + flow::LayerTree* GetLastLayerTree(); - virtual void DrawLastLayerTree() = 0; + void DrawLastLayerTree(); - virtual flow::TextureRegistry& GetTextureRegistry() = 0; + flow::TextureRegistry* GetTextureRegistry(); - virtual void Draw( - fxl::RefPtr> pipeline) = 0; + void Draw(fxl::RefPtr> pipeline); - // Set a callback to be called once when the next frame is drawn. - virtual void AddNextFrameCallback(fxl::Closure nextFrameCallback) = 0; + enum class ScreenshotType { + SkiaPicture, + UncompressedImage, // In kN32_SkColorType format + CompressedImage, + }; - virtual void SetTextureRegistry(flow::TextureRegistry* textureRegistry) = 0; + struct Screenshot { + sk_sp data; + SkISize frame_size = SkISize::MakeEmpty(); + + Screenshot() {} + + Screenshot(sk_sp p_data, SkISize p_size) + : data(std::move(p_data)), frame_size(p_size) {} + }; + + Screenshot ScreenshotLastLayerTree(ScreenshotType type, bool base64_encode); + + // Sets a callback that will be executed after the next frame is submitted to + // the surface on the GPU task runner. + void SetNextFrameCallback(fxl::Closure callback); + + private: + blink::TaskRunners task_runners_; + std::unique_ptr surface_; + std::unique_ptr compositor_context_; + std::unique_ptr last_layer_tree_; + fxl::Closure next_frame_callback_; + fml::WeakPtr weak_prototype_; + fml::WeakPtrFactory weak_factory_; + + void DoDraw(std::unique_ptr layer_tree); + + bool DrawToSurface(flow::LayerTree& layer_tree); + + void FireNextFrameCallbackIfPresent(); + + FXL_DISALLOW_COPY_AND_ASSIGN(Rasterizer); }; } // namespace shell diff --git a/shell/common/run_configuration.cc b/shell/common/run_configuration.cc new file mode 100644 index 0000000000000..7fb385fb4d9dc --- /dev/null +++ b/shell/common/run_configuration.cc @@ -0,0 +1,80 @@ +// 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/shell/common/run_configuration.h" + +#include + +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/assets/zip_asset_store.h" +#include "flutter/fml/file.h" +#include "flutter/runtime/dart_vm.h" + +namespace shell { + +RunConfiguration RunConfiguration::InferFromSettings( + const blink::Settings& settings) { + auto asset_manager = fxl::MakeRefCounted(); + + asset_manager->PushBack(std::make_unique( + fml::Duplicate(settings.assets_dir))); + + asset_manager->PushBack( + std::make_unique(fml::OpenFile( + settings.assets_path.c_str(), fml::OpenPermission::kRead, true))); + + asset_manager->PushBack( + std::make_unique(settings.flx_path)); + + return {IsolateConfiguration::InferFromSettings(settings, asset_manager), + asset_manager}; +} + +RunConfiguration::RunConfiguration( + std::unique_ptr configuration) + : RunConfiguration(std::move(configuration), + fxl::MakeRefCounted()) {} + +RunConfiguration::RunConfiguration( + std::unique_ptr configuration, + fxl::RefPtr asset_manager) + : isolate_configuration_(std::move(configuration)), + asset_manager_(std::move(asset_manager)) {} + +RunConfiguration::RunConfiguration(RunConfiguration&&) = default; + +RunConfiguration::~RunConfiguration() = default; + +bool RunConfiguration::IsValid() const { + return asset_manager_ && isolate_configuration_; +} + +bool RunConfiguration::AddAssetResolver( + std::unique_ptr resolver) { + if (!resolver || !resolver->IsValid()) { + return false; + } + + asset_manager_->PushBack(std::move(resolver)); + return true; +} + +void RunConfiguration::SetEntrypoint(std::string entrypoint) { + entrypoint_ = std::move(entrypoint); +} + +fxl::RefPtr RunConfiguration::GetAssetManager() const { + return asset_manager_; +} + +const std::string& RunConfiguration::GetEntrypoint() const { + return entrypoint_; +} + +std::unique_ptr +RunConfiguration::TakeIsolateConfiguration() { + return std::move(isolate_configuration_); +} + +} // namespace shell diff --git a/shell/common/run_configuration.h b/shell/common/run_configuration.h new file mode 100644 index 0000000000000..59aa07566685c --- /dev/null +++ b/shell/common/run_configuration.h @@ -0,0 +1,56 @@ +// 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_SHELL_COMMON_RUN_CONFIGURATION_H_ +#define FLUTTER_SHELL_COMMON_RUN_CONFIGURATION_H_ + +#include +#include + +#include "flutter/assets/asset_manager.h" +#include "flutter/assets/asset_resolver.h" +#include "flutter/common/settings.h" +#include "flutter/fml/mapping.h" +#include "flutter/shell/common/isolate_configuration.h" +#include "lib/fxl/files/unique_fd.h" +#include "lib/fxl/macros.h" + +namespace shell { + +class RunConfiguration { + public: + static RunConfiguration InferFromSettings(const blink::Settings& settings); + + RunConfiguration(std::unique_ptr configuration); + + RunConfiguration(std::unique_ptr configuration, + fxl::RefPtr asset_manager); + + RunConfiguration(RunConfiguration&&); + + ~RunConfiguration(); + + bool IsValid() const; + + bool AddAssetResolver(std::unique_ptr resolver); + + void SetEntrypoint(std::string entrypoint); + + fxl::RefPtr GetAssetManager() const; + + const std::string& GetEntrypoint() const; + + std::unique_ptr TakeIsolateConfiguration(); + + private: + std::unique_ptr isolate_configuration_; + fxl::RefPtr asset_manager_; + std::string entrypoint_ = "main"; + + FXL_DISALLOW_COPY_AND_ASSIGN(RunConfiguration); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_COMMON_RUN_CONFIGURATION_H_ diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 14f8fee84bb5f..53527a996bd76 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2,362 +2,859 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#define RAPIDJSON_HAS_STDSTRING 1 + #include "flutter/shell/common/shell.h" -#include #include #include #include -#include "flutter/common/settings.h" -#include "flutter/common/threads.h" +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/fml/file.h" #include "flutter/fml/icu_util.h" #include "flutter/fml/message_loop.h" -#include "flutter/fml/trace_event.h" -#include "flutter/runtime/dart_init.h" +#include "flutter/glue/trace_event.h" +#include "flutter/runtime/dart_vm.h" #include "flutter/shell/common/engine.h" -#include "flutter/shell/common/platform_view_service_protocol.h" #include "flutter/shell/common/skia_event_tracer_impl.h" #include "flutter/shell/common/switches.h" +#include "flutter/shell/common/vsync_waiter.h" #include "lib/fxl/files/unique_fd.h" +#include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/logging.h" #include "third_party/dart/runtime/include/dart_tools_api.h" #include "third_party/skia/include/core/SkGraphics.h" namespace shell { -namespace { -static Shell* g_shell = nullptr; +std::unique_ptr Shell::CreateShellOnPlatformThread( + blink::TaskRunners task_runners, + blink::Settings settings, + Shell::CreateCallback on_create_platform_view, + Shell::CreateCallback on_create_rasterizer) { + if (!task_runners.IsValid()) { + return nullptr; + } + + auto shell = std::unique_ptr(new Shell(task_runners, settings)); + + // Create the platform view on the platform thread (this thread). + auto platform_view = on_create_platform_view(*shell.get()); + if (!platform_view || !platform_view->GetWeakPtr()) { + return nullptr; + } + + // Ask the platform view for the vsync waiter. This will be used by the engine + // to create the animator. + auto vsync_waiter = platform_view->CreateVSyncWaiter(); + if (!vsync_waiter) { + return nullptr; + } + + // Create the IO manager on the IO thread. The IO manager must be initialized + // first because it has state that the other subsystems depend on. It must + // first be booted and the necessary references obtained to initialize the + // other subsystems. + fxl::AutoResetWaitableEvent io_latch; + std::unique_ptr io_manager; + fml::WeakPtr resource_context; + fxl::RefPtr unref_queue; + auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner(); + fml::TaskRunner::RunNowOrPostTask( + io_task_runner, + [&io_latch, // + &io_manager, // + &resource_context, // + &unref_queue, // + &platform_view, // + io_task_runner // + ]() { + io_manager = std::make_unique( + platform_view->CreateResourceContext(), io_task_runner); + resource_context = io_manager->GetResourceContext(); + unref_queue = io_manager->GetSkiaUnrefQueue(); + io_latch.Signal(); + }); + io_latch.Wait(); + + // Create the rasterizer on the GPU thread. + fxl::AutoResetWaitableEvent gpu_latch; + std::unique_ptr rasterizer; + fml::TaskRunner::RunNowOrPostTask( + task_runners.GetGPUTaskRunner(), [&gpu_latch, // + &rasterizer, // + on_create_rasterizer, // + shell = shell.get() // + ]() { + if (auto new_rasterizer = on_create_rasterizer(*shell)) { + rasterizer = std::move(new_rasterizer); + } + gpu_latch.Signal(); + }); + + // Create the engine on the UI thread. + fxl::AutoResetWaitableEvent ui_latch; + std::unique_ptr engine; + fml::TaskRunner::RunNowOrPostTask( + shell->GetTaskRunners().GetUITaskRunner(), + fxl::MakeCopyable([&ui_latch, // + &engine, // + shell = shell.get(), // + vsync_waiter = std::move(vsync_waiter), // + resource_context = std::move(resource_context), // + unref_queue = std::move(unref_queue) // + ]() mutable { + const auto& task_runners = shell->GetTaskRunners(); + + // The animator is owned by the UI thread but it gets its vsync pulses + // from the platform. + auto animator = std::make_unique(*shell, task_runners, + std::move(vsync_waiter)); + + engine = std::make_unique(*shell, // + shell->GetDartVM(), // + task_runners, // + shell->GetSettings(), // + std::move(animator), // + std::move(resource_context), // + std::move(unref_queue) // + ); + ui_latch.Signal(); + })); + + gpu_latch.Wait(); + ui_latch.Wait(); + // We are already on the platform thread. So there is no platform latch to + // wait on. + + if (!shell->Setup(std::move(platform_view), // + std::move(engine), // + std::move(rasterizer), // + std::move(io_manager)) // + ) { + return nullptr; + } + + return shell; +} + +std::unique_ptr Shell::Create( + blink::TaskRunners task_runners, + blink::Settings settings, + Shell::CreateCallback on_create_platform_view, + Shell::CreateCallback on_create_rasterizer) { + if (!task_runners.IsValid() || !on_create_platform_view || + !on_create_rasterizer) { + return nullptr; + } + + fxl::AutoResetWaitableEvent latch; + std::unique_ptr shell; + fml::TaskRunner::RunNowOrPostTask( + task_runners.GetPlatformTaskRunner(), + [&latch, &shell, task_runners = std::move(task_runners), settings, + on_create_platform_view, on_create_rasterizer]() { + shell = CreateShellOnPlatformThread(std::move(task_runners), settings, + on_create_platform_view, + on_create_rasterizer); + latch.Signal(); + }); + latch.Wait(); + return shell; +} + +Shell::Shell(blink::TaskRunners task_runners, blink::Settings settings) + : task_runners_(std::move(task_runners)), + settings_(std::move(settings)), + vm_(blink::DartVM::ForProcess(settings_)) { + FXL_DCHECK(task_runners_.IsValid()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + if (settings_.icu_data_path.size() != 0) { + fml::icu::InitializeICU(settings_.icu_data_path); + } else { + FXL_DLOG(WARNING) << "Skipping ICU initialization in the shell."; + } + + if (settings_.trace_skia) { + InitSkiaEventTracer(settings_.trace_skia); + } -template -bool GetSwitchValue(const fxl::CommandLine& command_line, - Switch sw, - T* result) { - std::string switch_string; + if (!settings_.skia_deterministic_rendering_on_cpu) { + SkGraphics::Init(); + } else { + FXL_DLOG(INFO) << "Skia deterministic rendering is enabled."; + } - if (!command_line.GetOptionValue(FlagForSwitch(sw), &switch_string)) { + // Install service protocol handlers. + + service_protocol_handlers_[blink::ServiceProtocol::kScreenshotExtensionName + .ToString()] = { + task_runners_.GetGPUTaskRunner(), + std::bind(&Shell::OnServiceProtocolScreenshot, this, + std::placeholders::_1, std::placeholders::_2)}; + service_protocol_handlers_[blink::ServiceProtocol::kScreenshotSkpExtensionName + .ToString()] = { + task_runners_.GetGPUTaskRunner(), + std::bind(&Shell::OnServiceProtocolScreenshotSKP, this, + std::placeholders::_1, std::placeholders::_2)}; + service_protocol_handlers_[blink::ServiceProtocol::kRunInViewExtensionName + .ToString()] = { + task_runners_.GetUITaskRunner(), + std::bind(&Shell::OnServiceProtocolRunInView, this, std::placeholders::_1, + std::placeholders::_2)}; + service_protocol_handlers_ + [blink::ServiceProtocol::kFlushUIThreadTasksExtensionName.ToString()] = { + task_runners_.GetUITaskRunner(), + std::bind(&Shell::OnServiceProtocolFlushUIThreadTasks, this, + std::placeholders::_1, std::placeholders::_2)}; + service_protocol_handlers_ + [blink::ServiceProtocol::kSetAssetBundlePathExtensionName.ToString()] = { + task_runners_.GetUITaskRunner(), + std::bind(&Shell::OnServiceProtocolSetAssetBundlePath, this, + std::placeholders::_1, std::placeholders::_2)}; +} + +Shell::~Shell() { + if (auto vm = blink::DartVM::ForProcessIfInitialized()) { + vm->GetServiceProtocol().RemoveHandler(this); + } + + fxl::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch; + + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetUITaskRunner(), + fxl::MakeCopyable([engine = std::move(engine_), &ui_latch]() mutable { + engine.reset(); + ui_latch.Signal(); + })); + ui_latch.Wait(); + + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetGPUTaskRunner(), + fxl::MakeCopyable( + [rasterizer = std::move(rasterizer_), &gpu_latch]() mutable { + rasterizer.reset(); + gpu_latch.Signal(); + })); + gpu_latch.Wait(); + + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetIOTaskRunner(), + fxl::MakeCopyable( + [io_manager = std::move(io_manager_), &io_latch]() mutable { + io_manager.reset(); + io_latch.Signal(); + })); + + io_latch.Wait(); + + // The platform view must go last because it may be holding onto platform side + // counterparts to resources owned by subsystems running on other threads. For + // example, the NSOpenGLContext on the Mac. + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetPlatformTaskRunner(), + fxl::MakeCopyable([platform_view = std::move(platform_view_), + &platform_latch]() mutable { + platform_view.reset(); + platform_latch.Signal(); + })); + platform_latch.Wait(); +} + +bool Shell::IsSetup() const { + return is_setup_; +} + +bool Shell::Setup(std::unique_ptr platform_view, + std::unique_ptr engine, + std::unique_ptr rasterizer, + std::unique_ptr io_manager) { + if (is_setup_) { return false; } - std::stringstream stream(switch_string); - T value = 0; - if (stream >> value) { - *result = value; - return true; + if (!platform_view || !engine || !rasterizer || !io_manager) { + return false; } - return false; + platform_view_ = std::move(platform_view); + engine_ = std::move(engine); + rasterizer_ = std::move(rasterizer); + io_manager_ = std::move(io_manager); + + is_setup_ = true; + + if (auto vm = blink::DartVM::ForProcessIfInitialized()) { + vm->GetServiceProtocol().AddHandler(this); + } + + return true; } -} // namespace +const blink::Settings& Shell::GetSettings() const { + return settings_; +} -Shell::Shell(fxl::CommandLine command_line) - : command_line_(std::move(command_line)) { - FXL_DCHECK(!g_shell); +const blink::TaskRunners& Shell::GetTaskRunners() const { + return task_runners_; +} - gpu_thread_.reset(new fml::Thread("gpu_thread")); - ui_thread_.reset(new fml::Thread("ui_thread")); - io_thread_.reset(new fml::Thread("io_thread")); +fml::WeakPtr Shell::GetRasterizer() { + FXL_DCHECK(is_setup_); + return rasterizer_->GetWeakPtr(); +} - // Since we are not using fml::Thread, we need to initialize the message loop - // manually. - fml::MessageLoop::EnsureInitializedForCurrentThread(); - blink::Threads threads(fml::MessageLoop::GetCurrent().GetTaskRunner(), - gpu_thread_->GetTaskRunner(), - ui_thread_->GetTaskRunner(), - io_thread_->GetTaskRunner()); - blink::Threads::Set(threads); +fml::WeakPtr Shell::GetEngine() { + FXL_DCHECK(is_setup_); + return engine_->GetWeakPtr(); +} - blink::Threads::Gpu()->PostTask([this]() { InitGpuThread(); }); - blink::Threads::UI()->PostTask([this]() { InitUIThread(); }); +fml::WeakPtr Shell::GetPlatformView() { + FXL_DCHECK(is_setup_); + return platform_view_->GetWeakPtr(); +} - blink::SetRegisterNativeServiceProtocolExtensionHook( - PlatformViewServiceProtocol::RegisterHook); +const blink::DartVM& Shell::GetDartVM() const { + return *vm_; } -Shell::~Shell() {} +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewCreated(const PlatformView& view, + std::unique_ptr surface) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); -void Shell::InitStandalone(fxl::CommandLine command_line, - std::string icu_data_path, - std::string application_library_path, - std::string bundle_path) { - TRACE_EVENT0("flutter", "Shell::InitStandalone"); + // Note: + // This is a synchronous operation because certain platforms depend on + // setup/suspension of all activities that may be interacting with the GPU in + // a synchronous fashion. - fml::icu::InitializeICU(icu_data_path); + fxl::AutoResetWaitableEvent latch; + auto gpu_task = fxl::MakeCopyable([rasterizer = rasterizer_->GetWeakPtr(), // + surface = std::move(surface), // + &latch]() mutable { + if (rasterizer) { + rasterizer->Setup(std::move(surface)); + } + // Step 2: All done. Signal the latch that the platform thread is waiting + // on. + latch.Signal(); + }); - if (!command_line.HasOption( - FlagForSwitch(Switch::SkiaDeterministicRendering))) - SkGraphics::Init(); + auto ui_task = [engine = engine_->GetWeakPtr(), // + gpu_task_runner = task_runners_.GetGPUTaskRunner(), // + gpu_task // + ] { + if (engine) { + engine->OnOutputSurfaceCreated(); + } + // Step 1: Next, tell the GPU thread that it should create a surface for its + // rasterizer. + fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task); + }; + + // Step 0: Post a task onto the UI thread to tell the engine that it has an + // output surface. + fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task); + latch.Wait(); +} - blink::Settings settings; - settings.application_library_path = application_library_path; +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewDestroyed(const PlatformView& view) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - // Enable Observatory - settings.enable_observatory = - !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory)); + // Note: + // This is a synchronous operation because certain platforms depend on + // setup/suspension of all activities that may be interacting with the GPU in + // a synchronous fashion. + + fxl::AutoResetWaitableEvent latch; - // Set Observatory Port - if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryPort))) { - if (!GetSwitchValue(command_line, Switch::DeviceObservatoryPort, - &settings.observatory_port)) { - FXL_LOG(INFO) - << "Observatory port specified was malformed. Will default to " - << settings.observatory_port; + auto gpu_task = [rasterizer = rasterizer_->GetWeakPtr(), &latch]() { + if (rasterizer) { + rasterizer->Teardown(); } - } + // Step 2: All done. Signal the latch that the platform thread is waiting + // on. + latch.Signal(); + }; + + auto ui_task = [engine = engine_->GetWeakPtr(), + gpu_task_runner = task_runners_.GetGPUTaskRunner(), + gpu_task]() { + if (engine) { + engine->OnOutputSurfaceDestroyed(); + } + // Step 1: Next, tell the GPU thread that its rasterizer should suspend + // access to the underlying surface. + fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task); + }; + + // Step 0: Post a task onto the UI thread to tell the engine that its output + // surface is about to go away. + fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task); + latch.Wait(); +} + +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewSetViewportMetrics( + const PlatformView& view, + const blink::ViewportMetrics& metrics) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetUITaskRunner()->PostTask( + [engine = engine_->GetWeakPtr(), metrics]() { + if (engine) { + engine->SetViewportMetrics(metrics); + } + }); +} + +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewDispatchPlatformMessage( + const PlatformView& view, + fxl::RefPtr message) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetUITaskRunner()->PostTask( + [engine = engine_->GetWeakPtr(), message = std::move(message)] { + if (engine) { + engine->DispatchPlatformMessage(std::move(message)); + } + }); +} - // Checked mode overrides. - settings.dart_non_checked_mode = - command_line.HasOption(FlagForSwitch(Switch::DartNonCheckedMode)); +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewDispatchPointerDataPacket( + const PlatformView& view, + std::unique_ptr packet) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + task_runners_.GetUITaskRunner()->PostTask(fxl::MakeCopyable( + [engine = engine_->GetWeakPtr(), packet = std::move(packet)] { + if (engine) { + engine->DispatchPointerDataPacket(*packet); + } + })); +} - settings.ipv6 = command_line.HasOption(FlagForSwitch(Switch::IPv6)); +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewDispatchSemanticsAction(const PlatformView& view, + int32_t id, + blink::SemanticsAction action, + std::vector args) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetUITaskRunner()->PostTask( + [engine = engine_->GetWeakPtr(), id, action, args = std::move(args)] { + if (engine) { + engine->DispatchSemanticsAction(id, action, std::move(args)); + } + }); +} - settings.start_paused = - command_line.HasOption(FlagForSwitch(Switch::StartPaused)); +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewSetSemanticsEnabled(const PlatformView& view, + bool enabled) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetUITaskRunner()->PostTask( + [engine = engine_->GetWeakPtr(), enabled] { + if (engine) { + engine->SetSemanticsEnabled(enabled); + } + }); +} - settings.enable_dart_profiling = - command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling)); +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewRegisterTexture( + const PlatformView& view, + std::shared_ptr texture) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetGPUTaskRunner()->PostTask( + [rasterizer = rasterizer_->GetWeakPtr(), texture] { + if (rasterizer) { + if (auto registry = rasterizer->GetTextureRegistry()) { + registry->RegisterTexture(texture); + } + } + }); +} - settings.enable_software_rendering = - command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering)); +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewUnregisterTexture(const PlatformView& view, + int64_t texture_id) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetGPUTaskRunner()->PostTask( + [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { + if (rasterizer) { + if (auto registry = rasterizer->GetTextureRegistry()) { + registry->UnregisterTexture(texture_id); + } + } + }); +} - settings.using_blink = - command_line.HasOption(FlagForSwitch(Switch::EnableBlink)); +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewMarkTextureFrameAvailable(const PlatformView& view, + int64_t texture_id) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - settings.endless_trace_buffer = - command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer)); + // Tell the rasterizer that one of its textures has a new frame available. + task_runners_.GetGPUTaskRunner()->PostTask( + [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { + auto registry = rasterizer->GetTextureRegistry(); - settings.trace_startup = - command_line.HasOption(FlagForSwitch(Switch::TraceStartup)); + if (!registry) { + return; + } - command_line.GetOptionValue(FlagForSwitch(Switch::AotSnapshotPath), - &settings.aot_snapshot_path); + auto texture = registry->GetTexture(texture_id); - command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotData), - &settings.aot_vm_snapshot_data_filename); + if (!texture) { + return; + } - command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotInstructions), - &settings.aot_vm_snapshot_instr_filename); + texture->MarkNewFrameAvailable(); + }); - command_line.GetOptionValue(FlagForSwitch(Switch::AotIsolateSnapshotData), - &settings.aot_isolate_snapshot_data_filename); + // Schedule a new frame without having to rebuild the layer tree. + task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr()]() { + if (engine) { + engine->ScheduleFrame(false); + } + }); +} - command_line.GetOptionValue(FlagForSwitch(Switch::AotSharedLibraryPath), - &settings.aot_shared_library_path); +// |shell::PlatformView::Delegate| +void Shell::OnPlatformViewSetNextFrameCallback(const PlatformView& view, + fxl::Closure closure) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(&view == platform_view_.get()); + FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetGPUTaskRunner()->PostTask( + [rasterizer = rasterizer_->GetWeakPtr(), closure = std::move(closure)]() { + if (rasterizer) { + rasterizer->SetNextFrameCallback(std::move(closure)); + } + }); +} - command_line.GetOptionValue( - FlagForSwitch(Switch::AotIsolateSnapshotInstructions), - &settings.aot_isolate_snapshot_instr_filename); +// |shell::Animator::Delegate| +void Shell::OnAnimatorBeginFrame(const Animator& animator, + fxl::TimePoint frame_time) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath), - &settings.temp_directory_path); + if (engine_) { + engine_->BeginFrame(frame_time); + } +} - settings.use_test_fonts = - command_line.HasOption(FlagForSwitch(Switch::UseTestFonts)); +// |shell::Animator::Delegate| +void Shell::OnAnimatorNotifyIdle(const Animator& animator, int64_t deadline) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - std::string all_dart_flags; - if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags), - &all_dart_flags)) { - std::stringstream stream(all_dart_flags); - std::istream_iterator end; - for (std::istream_iterator it(stream); it != end; ++it) - settings.dart_flags.push_back(*it); + if (engine_) { + engine_->NotifyIdle(deadline); } +} - command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag); +// |shell::Animator::Delegate| +void Shell::OnAnimatorDraw( + const Animator& animator, + fxl::RefPtr> pipeline) { + FXL_DCHECK(is_setup_); + + task_runners_.GetGPUTaskRunner()->PostTask( + [rasterizer = rasterizer_->GetWeakPtr(), + pipeline = std::move(pipeline)]() { + if (rasterizer) { + rasterizer->Draw(pipeline); + } + }); +} - blink::Settings::Set(settings); +// |shell::Animator::Delegate| +void Shell::OnAnimatorDrawLastLayerTree(const Animator& animator) { + FXL_DCHECK(is_setup_); - Init(std::move(command_line), bundle_path); + task_runners_.GetGPUTaskRunner()->PostTask( + [rasterizer = rasterizer_->GetWeakPtr()]() { + if (rasterizer) { + rasterizer->DrawLastLayerTree(); + } + }); } -void Shell::Init(fxl::CommandLine command_line, - const std::string& bundle_path) { -#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE - bool trace_skia = command_line.HasOption(FlagForSwitch(Switch::TraceSkia)); - InitSkiaEventTracer(trace_skia); -#endif +// |shell::Engine::Delegate| +void Shell::OnEngineUpdateSemantics(const Engine& engine, + blink::SemanticsNodeUpdates update) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - FXL_DCHECK(!g_shell); - g_shell = new Shell(std::move(command_line)); - blink::Threads::UI()->PostTask( - [bundle_path]() { Engine::Init(bundle_path); }); + task_runners_.GetPlatformTaskRunner()->PostTask( + [view = platform_view_->GetWeakPtr(), update = std::move(update)] { + if (view) { + view->UpdateSemantics(std::move(update)); + } + }); } -Shell& Shell::Shared() { - FXL_DCHECK(g_shell); - return *g_shell; +// |shell::Engine::Delegate| +void Shell::OnEngineHandlePlatformMessage( + const Engine& engine, + fxl::RefPtr message) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetPlatformTaskRunner()->PostTask( + [view = platform_view_->GetWeakPtr(), message = std::move(message)]() { + if (view) { + view->HandlePlatformMessage(std::move(message)); + } + }); } -const fxl::CommandLine& Shell::GetCommandLine() const { - return command_line_; +// |blink::ServiceProtocol::Handler| +fxl::RefPtr Shell::GetServiceProtocolHandlerTaskRunner( + fxl::StringView method) const { + FXL_DCHECK(is_setup_); + auto found = service_protocol_handlers_.find(method.ToString()); + if (found != service_protocol_handlers_.end()) { + return found->second.first; + } + return task_runners_.GetUITaskRunner(); } -void Shell::InitGpuThread() { - gpu_thread_checker_.reset(new fxl::ThreadChecker()); +// |blink::ServiceProtocol::Handler| +bool Shell::HandleServiceProtocolMessage( + fxl::StringView method, // one if the extension names specified above. + const ServiceProtocolMap& params, + rapidjson::Document& response) { + auto found = service_protocol_handlers_.find(method.ToString()); + if (found != service_protocol_handlers_.end()) { + return found->second.second(params, response); + } + return false; } -void Shell::InitUIThread() { - ui_thread_checker_.reset(new fxl::ThreadChecker()); +// |blink::ServiceProtocol::Handler| +blink::ServiceProtocol::Handler::Description +Shell::GetServiceProtocolDescription() const { + return { + engine_->GetUIIsolateMainPort(), + engine_->GetUIIsolateName(), + }; } -void Shell::AddPlatformView(PlatformView* platform_view) { - if (platform_view == nullptr) { - return; +static void ServiceProtocolParameterError(rapidjson::Document& response, + std::string parameter_name) { + auto& allocator = response.GetAllocator(); + response.SetObject(); + const int64_t kInvalidParams = -32602; + response.AddMember("code", kInvalidParams, allocator); + response.AddMember("message", "Invalid params", allocator); + { + rapidjson::Value details(rapidjson::kObjectType); + details.AddMember("details", parameter_name, allocator); + response.AddMember("data", details, allocator); } - std::lock_guard lock(platform_views_mutex_); - platform_views_.insert(platform_view); } -void Shell::RemovePlatformView(PlatformView* platform_view) { - if (platform_view == nullptr) { - return; +// Service protocol handler +bool Shell::OnServiceProtocolScreenshot( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response) { + FXL_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread()); + auto screenshot = rasterizer_->ScreenshotLastLayerTree( + Rasterizer::ScreenshotType::CompressedImage, true); + if (screenshot.data) { + response.SetObject(); + auto& allocator = response.GetAllocator(); + response.AddMember("type", "Screenshot", allocator); + rapidjson::Value image; + image.SetString(static_cast(screenshot.data->data()), + screenshot.data->size(), allocator); + response.AddMember("screenshot", image, allocator); + return true; } - std::lock_guard lock(platform_views_mutex_); - platform_views_.erase(platform_view); + ServiceProtocolParameterError(response, + "Could not capture image screenshot."); + return false; } -void Shell::IteratePlatformViews( - std::function iterator) const { - if (iterator == nullptr) { - return; +// Service protocol handler +bool Shell::OnServiceProtocolScreenshotSKP( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response) { + FXL_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread()); + auto screenshot = rasterizer_->ScreenshotLastLayerTree( + Rasterizer::ScreenshotType::SkiaPicture, true); + if (screenshot.data) { + response.SetObject(); + auto& allocator = response.GetAllocator(); + response.AddMember("type", "ScreenshotSkp", allocator); + rapidjson::Value skp; + skp.SetString(static_cast(screenshot.data->data()), + screenshot.data->size(), allocator); + response.AddMember("skp", skp, allocator); + return true; } - std::lock_guard lock(platform_views_mutex_); - for (PlatformView* view : platform_views_) { - if (!iterator(view)) { - return; - } + ServiceProtocolParameterError(response, "Could not capture SKP screenshot."); + return false; +} + +// Service protocol handler +bool Shell::OnServiceProtocolRunInView( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response) { + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); + + if (params.count("mainScript") == 0) { + ServiceProtocolParameterError(response, + "'mainScript' parameter is missing."); + return false; + } + + if (params.count("packagesFile") == 0) { + ServiceProtocolParameterError(response, + "'packagesFile' parameter is missing."); + return false; } + + if (params.count("assetDirectory") == 0) { + ServiceProtocolParameterError(response, + "'assetDirectory' parameter is missing."); + return false; + } + + RunConfiguration configuration(IsolateConfiguration::CreateForSource( + params.at("mainScript").ToString(), + params.at("packagesFile").ToString())); + + configuration.AddAssetResolver(std::make_unique( + fml::OpenFile(params.at("assetDirectory").ToString().c_str(), + fml::OpenPermission::kRead, true))); + + auto& allocator = response.GetAllocator(); + response.SetObject(); + if (engine_->Restart(std::move(configuration))) { + response.AddMember("type", "Success", allocator); + auto new_description = GetServiceProtocolDescription(); + rapidjson::Value view(rapidjson::kObjectType); + new_description.Write(this, view, allocator); + response.AddMember("view", view, allocator); + return true; + } else { + FXL_DLOG(ERROR) << "Could not run configuration in engine."; + response.AddMember("type", "Failure", allocator); + return false; + } + + FXL_DCHECK(false); + return false; } -void Shell::RunInPlatformView(uintptr_t view_id, - const char* main_script, - const char* packages_file, - const char* asset_directory, - bool* view_existed, - int64_t* dart_isolate_id, - std::string* isolate_name) { - fxl::AutoResetWaitableEvent latch; - FXL_DCHECK(view_id != 0); - FXL_DCHECK(main_script); - FXL_DCHECK(packages_file); - FXL_DCHECK(asset_directory); - FXL_DCHECK(view_existed); - - blink::Threads::UI()->PostTask([this, view_id, main_script, packages_file, - asset_directory, view_existed, - dart_isolate_id, isolate_name, &latch]() { - RunInPlatformViewUIThread(view_id, main_script, packages_file, - asset_directory, view_existed, dart_isolate_id, - isolate_name, &latch); - }); - latch.Wait(); +// Service protocol handler +bool Shell::OnServiceProtocolFlushUIThreadTasks( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response) { + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); + // This API should not be invoked by production code. + // It can potentially starve the service isolate if the main isolate pauses + // at a breakpoint or is in an infinite loop. + // + // It should be invoked from the VM Service and and blocks it until UI thread + // tasks are processed. + response.SetObject(); + response.AddMember("type", "Success", response.GetAllocator()); + return true; } -void Shell::RunInPlatformViewUIThread(uintptr_t view_id, - const std::string& main, - const std::string& packages, - const std::string& assets_directory, - bool* view_existed, - int64_t* dart_isolate_id, - std::string* isolate_name, - fxl::AutoResetWaitableEvent* latch) { - FXL_DCHECK(ui_thread_checker_ && - ui_thread_checker_->IsCreationThreadCurrent()); - - *view_existed = false; - - IteratePlatformViews( - [view_id, // argument -#if !defined(OS_WIN) - // Using std::move on const references inside lambda capture is - // not supported on Windows for some reason. - assets_directory = std::move(assets_directory), // argument - main = std::move(main), // argument - packages = std::move(packages), // argument -#else - assets_directory, // argument - main, // argument - packages, // argument -#endif - &view_existed, // out - &dart_isolate_id, // out - &isolate_name // out - ](PlatformView* view) -> bool { - if (reinterpret_cast(view) != view_id) { - // Keep looking. - return true; - } - *view_existed = true; - view->RunFromSource(assets_directory, main, packages); - *dart_isolate_id = view->engine().GetUIIsolateMainPort(); - *isolate_name = view->engine().GetUIIsolateName(); - // We found the requested view. Stop iterating over platform views. - return false; - }); +// Service protocol handler +bool Shell::OnServiceProtocolSetAssetBundlePath( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response) { + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - latch->Signal(); -} + if (params.count("assetDirectory") == 0) { + ServiceProtocolParameterError(response, + "'assetDirectory' parameter is missing."); + return false; + } -void Shell::SetAssetBundlePathInPlatformView(uintptr_t view_id, - const char* asset_directory, - bool* view_existed, - int64_t* dart_isolate_id, - std::string* isolate_name) { - fxl::AutoResetWaitableEvent latch; - FXL_DCHECK(view_id != 0); - FXL_DCHECK(asset_directory); - FXL_DCHECK(view_existed); - - blink::Threads::UI()->PostTask([this, view_id, asset_directory, view_existed, - dart_isolate_id, isolate_name, &latch]() { - SetAssetBundlePathInPlatformViewUIThread(view_id, asset_directory, - view_existed, dart_isolate_id, - isolate_name, &latch); - }); - latch.Wait(); + auto& allocator = response.GetAllocator(); + response.SetObject(); + + auto asset_manager = fxl::MakeRefCounted(); + + asset_manager->PushFront(std::make_unique( + fml::OpenFile(params.at("assetDirectory").ToString().c_str(), + fml::OpenPermission::kRead, true))); + + if (engine_->UpdateAssetManager(std::move(asset_manager))) { + response.AddMember("type", "Success", allocator); + auto new_description = GetServiceProtocolDescription(); + rapidjson::Value view(rapidjson::kObjectType); + new_description.Write(this, view, allocator); + response.AddMember("view", view, allocator); + return true; + } else { + FXL_DLOG(ERROR) << "Could not update asset directory."; + response.AddMember("type", "Failure", allocator); + return false; + } + + FXL_DCHECK(false); + return false; } -void Shell::SetAssetBundlePathInPlatformViewUIThread( - uintptr_t view_id, - const std::string& assets_directory, - bool* view_existed, - int64_t* dart_isolate_id, - std::string* isolate_name, - fxl::AutoResetWaitableEvent* latch) { - FXL_DCHECK(ui_thread_checker_ && - ui_thread_checker_->IsCreationThreadCurrent()); - - *view_existed = false; - - IteratePlatformViews( - [view_id, // argument -#if !defined(OS_WIN) - // Using std::move on const references inside lambda capture is - // not supported on Windows for some reason. - // TODO(https://github.com/flutter/flutter/issues/13908): - // Investigate the root cause of the difference. - assets_directory = std::move(assets_directory), // argument -#else - assets_directory, // argument -#endif - &view_existed, // out - &dart_isolate_id, // out - &isolate_name // out - ](PlatformView* view) -> bool { - if (reinterpret_cast(view) != view_id) { - // Keep looking. - return true; +Rasterizer::Screenshot Shell::Screenshot( + Rasterizer::ScreenshotType screenshot_type, + bool base64_encode) { + TRACE_EVENT0("flutter", "Shell::Screenshot"); + fxl::AutoResetWaitableEvent latch; + Rasterizer::Screenshot screenshot; + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetGPUTaskRunner(), [&latch, // + rasterizer = GetRasterizer(), // + &screenshot, // + screenshot_type, // + base64_encode // + ]() { + if (rasterizer) { + screenshot = rasterizer->ScreenshotLastLayerTree(screenshot_type, + base64_encode); } - *view_existed = true; - view->SetAssetBundlePath(assets_directory); - *dart_isolate_id = view->engine().GetUIIsolateMainPort(); - *isolate_name = view->engine().GetUIIsolateName(); - // We found the requested view. Stop iterating over - // platform views. - return false; + latch.Signal(); }); - - latch->Signal(); + latch.Wait(); + return screenshot; } } // namespace shell diff --git a/shell/common/shell.h b/shell/common/shell.h index 92c315dcf2aa7..02a642b0ba40f 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -5,96 +5,214 @@ #ifndef SHELL_COMMON_SHELL_H_ #define SHELL_COMMON_SHELL_H_ -#include -#include - +#include +#include + +#include "flutter/common/settings.h" +#include "flutter/common/task_runners.h" +#include "flutter/flow/texture.h" +#include "flutter/fml/memory/thread_checker.h" +#include "flutter/fml/memory/weak_ptr.h" #include "flutter/fml/thread.h" -#include "flutter/shell/common/tracing_controller.h" -#include "lib/fxl/command_line.h" +#include "flutter/lib/ui/semantics/semantics_node.h" +#include "flutter/lib/ui/window/platform_message.h" +#include "flutter/runtime/service_protocol.h" +#include "flutter/shell/common/animator.h" +#include "flutter/shell/common/engine.h" +#include "flutter/shell/common/io_manager.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/surface.h" #include "lib/fxl/functional/closure.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_ptr.h" #include "lib/fxl/memory/weak_ptr.h" +#include "lib/fxl/strings/string_view.h" +#include "lib/fxl/synchronization/thread_annotations.h" #include "lib/fxl/synchronization/thread_checker.h" #include "lib/fxl/synchronization/waitable_event.h" -#include "lib/fxl/tasks/task_runner.h" namespace shell { -class PlatformView; - -class Shell { +class Shell final : public PlatformView::Delegate, + public Animator::Delegate, + public Engine::Delegate, + public blink::ServiceProtocol::Handler { public: + template + using CreateCallback = std::function(Shell&)>; + static std::unique_ptr Create( + blink::TaskRunners task_runners, + blink::Settings settings, + CreateCallback on_create_platform_view, + CreateCallback on_create_rasterizer); + ~Shell(); - static void InitStandalone(fxl::CommandLine command_line, - std::string icu_data_path = "", - std::string application_library_path = "", - std::string bundle_path = ""); + const blink::Settings& GetSettings() const; - static Shell& Shared(); + const blink::TaskRunners& GetTaskRunners() const; - const fxl::CommandLine& GetCommandLine() const; + fml::WeakPtr GetRasterizer(); - void AddPlatformView(PlatformView* platform_view); + fml::WeakPtr GetEngine(); - void RemovePlatformView(PlatformView* platform_view); + fml::WeakPtr GetPlatformView(); - void IteratePlatformViews( - std::function iterator) const; + const blink::DartVM& GetDartVM() const; - // 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, - int64_t* dart_isolate_id, - std::string* isolate_name); + bool IsSetup() const; - void SetAssetBundlePathInPlatformView(uintptr_t view_id, - const char* asset_directory, - bool* view_existed, - int64_t* dart_isolate_id, - std::string* isolate_name); + Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, + bool base64_encode); private: - fxl::CommandLine command_line_; - std::unique_ptr gpu_thread_; - std::unique_ptr ui_thread_; - std::unique_ptr io_thread_; - std::unique_ptr gpu_thread_checker_; - std::unique_ptr ui_thread_checker_; - TracingController tracing_controller_; - mutable std::mutex platform_views_mutex_; - std::unordered_set platform_views_; - - static void Init(fxl::CommandLine command_line, - const std::string& bundle_path); - - Shell(fxl::CommandLine command_line); - - void InitGpuThread(); - - void InitUIThread(); - - void RunInPlatformViewUIThread(uintptr_t view_id, - const std::string& main, - const std::string& packages, - const std::string& assets_directory, - bool* view_existed, - int64_t* dart_isolate_id, - std::string* isolate_name, - fxl::AutoResetWaitableEvent* latch); - - void SetAssetBundlePathInPlatformViewUIThread( - uintptr_t view_id, - const std::string& main, - bool* view_existed, - int64_t* dart_isolate_id, - std::string* isolate_name, - fxl::AutoResetWaitableEvent* latch); + using ServiceProtocolHandler = std::function; + + const blink::TaskRunners task_runners_; + const blink::Settings settings_; + fxl::RefPtr vm_; + std::unique_ptr platform_view_; // on platform task runner + std::unique_ptr engine_; // on UI task runner + std::unique_ptr rasterizer_; // on GPU task runner + std::unique_ptr io_manager_; // on IO task runner + + std::unordered_map, + ServiceProtocolHandler> // task-runner/function + // pair + > + service_protocol_handlers_; + bool is_setup_ = false; + + Shell(blink::TaskRunners task_runners, blink::Settings settings); + + static std::unique_ptr CreateShellOnPlatformThread( + blink::TaskRunners task_runners, + blink::Settings settings, + Shell::CreateCallback on_create_platform_view, + Shell::CreateCallback on_create_rasterizer); + + bool Setup(std::unique_ptr platform_view, + std::unique_ptr engine, + std::unique_ptr rasterizer, + std::unique_ptr io_manager); + + // |shell::PlatformView::Delegate| + void OnPlatformViewCreated(const PlatformView& view, + std::unique_ptr surface) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewDestroyed(const PlatformView& view) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewSetViewportMetrics( + const PlatformView& view, + const blink::ViewportMetrics& metrics) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewDispatchPlatformMessage( + const PlatformView& view, + fxl::RefPtr message) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewDispatchPointerDataPacket( + const PlatformView& view, + std::unique_ptr packet) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewDispatchSemanticsAction( + const PlatformView& view, + int32_t id, + blink::SemanticsAction action, + std::vector args) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewSetSemanticsEnabled(const PlatformView& view, + bool enabled) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewRegisterTexture( + const PlatformView& view, + std::shared_ptr texture) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewUnregisterTexture(const PlatformView& view, + int64_t texture_id) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewMarkTextureFrameAvailable(const PlatformView& view, + int64_t texture_id) override; + + // |shell::PlatformView::Delegate| + void OnPlatformViewSetNextFrameCallback(const PlatformView& view, + fxl::Closure closure) override; + + // |shell::Animator::Delegate| + void OnAnimatorBeginFrame(const Animator& animator, + fxl::TimePoint frame_time) override; + + // |shell::Animator::Delegate| + void OnAnimatorNotifyIdle(const Animator& animator, + int64_t deadline) override; + + // |shell::Animator::Delegate| + void OnAnimatorDraw( + const Animator& animator, + fxl::RefPtr> pipeline) override; + + // |shell::Animator::Delegate| + void OnAnimatorDrawLastLayerTree(const Animator& animator) override; + + // |shell::Engine::Delegate| + void OnEngineUpdateSemantics(const Engine& engine, + blink::SemanticsNodeUpdates update) override; + + // |shell::Engine::Delegate| + void OnEngineHandlePlatformMessage( + const Engine& engine, + fxl::RefPtr message) override; + + // |blink::ServiceProtocol::Handler| + fxl::RefPtr GetServiceProtocolHandlerTaskRunner( + fxl::StringView method) const override; + + // |blink::ServiceProtocol::Handler| + bool HandleServiceProtocolMessage( + fxl::StringView method, // one if the extension names specified above. + const ServiceProtocolMap& params, + rapidjson::Document& response) override; + + // |blink::ServiceProtocol::Handler| + blink::ServiceProtocol::Handler::Description GetServiceProtocolDescription() + const override; + + // Service protocol handler + bool OnServiceProtocolScreenshot( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response); + + // Service protocol handler + bool OnServiceProtocolScreenshotSKP( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response); + + // Service protocol handler + bool OnServiceProtocolRunInView( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response); + + // Service protocol handler + bool OnServiceProtocolFlushUIThreadTasks( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response); + + // Service protocol handler + bool OnServiceProtocolSetAssetBundlePath( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response); FXL_DISALLOW_COPY_AND_ASSIGN(Shell); }; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc new file mode 100644 index 0000000000000..67689341a1586 --- /dev/null +++ b/shell/common/shell_unittests.cc @@ -0,0 +1,133 @@ +// 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. + +#define FML_USED_ON_EMBEDDER + +#include +#include +#include + +#include "flutter/fml/message_loop.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/thread_host.h" +#include "gtest/gtest.h" +#include "lib/fxl/synchronization/waitable_event.h" + +#define CURRENT_TEST_NAME \ + std::string { \ + ::testing::UnitTest::GetInstance()->current_test_info()->name() \ + } + +namespace shell { + +TEST(ShellTest, InitializeWithInvalidThreads) { + blink::Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + settings.using_blink = false; + blink::TaskRunners task_runners("test", nullptr, nullptr, nullptr, nullptr); + auto shell = Shell::Create( + std::move(task_runners), settings, + [](Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); + }, + [](Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }); + ASSERT_FALSE(shell); +} + +TEST(ShellTest, InitializeWithDifferentThreads) { + blink::Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + settings.using_blink = false; + ThreadHost thread_host("io.flutter.test." + CURRENT_TEST_NAME + ".", + ThreadHost::Type::Platform | ThreadHost::Type::GPU | + ThreadHost::Type::IO | ThreadHost::Type::UI); + blink::TaskRunners task_runners("test", + thread_host.platform_thread->GetTaskRunner(), + thread_host.gpu_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + auto shell = Shell::Create( + std::move(task_runners), settings, + [](Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); + }, + [](Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }); + ASSERT_TRUE(shell); +} + +TEST(ShellTest, InitializeWithSingleThread) { + blink::Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + settings.using_blink = false; + ThreadHost thread_host("io.flutter.test." + CURRENT_TEST_NAME + ".", + ThreadHost::Type::Platform); + auto task_runner = thread_host.platform_thread->GetTaskRunner(); + blink::TaskRunners task_runners("test", task_runner, task_runner, task_runner, + task_runner); + auto shell = Shell::Create( + std::move(task_runners), settings, + [](Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); + }, + [](Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }); + ASSERT_TRUE(shell); +} + +TEST(ShellTest, InitializeWithSingleThreadWhichIsTheCallingThread) { + blink::Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + settings.using_blink = false; + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); + blink::TaskRunners task_runners("test", task_runner, task_runner, task_runner, + task_runner); + auto shell = Shell::Create( + std::move(task_runners), settings, + [](Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); + }, + [](Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }); + ASSERT_TRUE(shell); +} + +TEST(ShellTest, InitializeWithMultipleThreadButCallingThreadAsPlatformThread) { + blink::Settings settings = {}; + settings.task_observer_add = [](intptr_t, fxl::Closure) {}; + settings.task_observer_remove = [](intptr_t) {}; + settings.using_blink = false; + ThreadHost thread_host( + "io.flutter.test." + CURRENT_TEST_NAME + ".", + ThreadHost::Type::GPU | ThreadHost::Type::IO | ThreadHost::Type::UI); + fml::MessageLoop::EnsureInitializedForCurrentThread(); + blink::TaskRunners task_runners( + "test", fml::MessageLoop::GetCurrent().GetTaskRunner(), + thread_host.gpu_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + auto shell = Shell::Create( + std::move(task_runners), settings, + [](Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); + }, + [](Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }); + ASSERT_TRUE(shell); +} + +} // namespace shell diff --git a/shell/common/surface.cc b/shell/common/surface.cc index 01d288a5e5085..228647e8b3512 100644 --- a/shell/common/surface.cc +++ b/shell/common/surface.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/shell/common/surface.h" + #include "lib/fxl/logging.h" #include "third_party/skia/include/core/SkColorSpaceXformCanvas.h" #include "third_party/skia/include/core/SkSurface.h" @@ -59,27 +60,22 @@ bool SurfaceFrame::PerformSubmit() { return false; } -Surface::Surface() : scale_(1.0) {} - -Surface::~Surface() = default; +Surface::Surface() : Surface(std::make_unique()) {} -bool Surface::SupportsScaling() const { - return false; +Surface::Surface(std::unique_ptr compositor_context) + : compositor_context_(std::move(compositor_context)) { + FXL_DCHECK(compositor_context_); + // TODO: Get rid of these explicit calls and move the logic to the c/dtors of + // the compositor context. + compositor_context_->OnGrContextCreated(); } -double Surface::GetScale() const { - return scale_; +Surface::~Surface() { + compositor_context_->OnGrContextDestroyed(); } -void Surface::SetScale(double scale) { - static constexpr double kMaxScale = 1.0; - static constexpr double kMinScale = 0.25; - if (scale > kMaxScale) { - scale = kMaxScale; - } else if (scale < kMinScale) { - scale = kMinScale; - } - scale_ = scale; +flow::CompositorContext& Surface::GetCompositorContext() { + return *compositor_context_; } } // namespace shell diff --git a/shell/common/surface.h b/shell/common/surface.h index 906480237f416..6133a7d519fff 100644 --- a/shell/common/surface.h +++ b/shell/common/surface.h @@ -7,7 +7,7 @@ #include -#include "lib/fxl/compiler_specific.h" +#include "flutter/flow/compositor_context.h" #include "lib/fxl/macros.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -45,6 +45,8 @@ class Surface { public: Surface(); + Surface(std::unique_ptr compositor_context); + virtual ~Surface(); virtual bool IsValid() = 0; @@ -53,14 +55,12 @@ class Surface { virtual GrContext* GetContext() = 0; - virtual bool SupportsScaling() const; - - double GetScale() const; - - void SetScale(double scale); + flow::CompositorContext& GetCompositorContext(); private: - double scale_; + std::unique_ptr compositor_context_; + + FXL_DISALLOW_COPY_AND_ASSIGN(Surface); }; } // namespace shell diff --git a/shell/common/switches.cc b/shell/common/switches.cc index c1c82ff166ac1..82da6ee180af8 100644 --- a/shell/common/switches.cc +++ b/shell/common/switches.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -90,4 +91,125 @@ const fxl::StringView FlagForSwitch(Switch swtch) { return fxl::StringView(); } +template +static bool GetSwitchValue(const fxl::CommandLine& command_line, + shell::Switch sw, + T* result) { + std::string switch_string; + + if (!command_line.GetOptionValue(shell::FlagForSwitch(sw), &switch_string)) { + return false; + } + + std::stringstream stream(switch_string); + T value = 0; + if (stream >> value) { + *result = value; + return true; + } + + return false; +} + +blink::Settings SettingsFromCommandLine(const fxl::CommandLine& command_line) { + blink::Settings settings = {}; + + // Enable Observatory + settings.enable_observatory = + !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory)); + + // Set Observatory Port + if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryPort))) { + if (!GetSwitchValue(command_line, Switch::DeviceObservatoryPort, + &settings.observatory_port)) { + FXL_LOG(INFO) + << "Observatory port specified was malformed. Will default to " + << settings.observatory_port; + } + } + + // Checked mode overrides. + settings.dart_non_checked_mode = + command_line.HasOption(FlagForSwitch(Switch::DartNonCheckedMode)); + + settings.ipv6 = command_line.HasOption(FlagForSwitch(Switch::IPv6)); + + settings.start_paused = + command_line.HasOption(FlagForSwitch(Switch::StartPaused)); + + settings.enable_dart_profiling = + command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling)); + + settings.enable_software_rendering = + command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering)); + + settings.using_blink = + command_line.HasOption(FlagForSwitch(Switch::EnableBlink)); + + settings.endless_trace_buffer = + command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer)); + + settings.trace_startup = + command_line.HasOption(FlagForSwitch(Switch::TraceStartup)); + + settings.skia_deterministic_rendering_on_cpu = + command_line.HasOption(FlagForSwitch(Switch::SkiaDeterministicRendering)); + + command_line.GetOptionValue(FlagForSwitch(Switch::FLX), &settings.flx_path); + + command_line.GetOptionValue(FlagForSwitch(Switch::FlutterAssetsDir), + &settings.assets_path); + + command_line.GetOptionValue(FlagForSwitch(Switch::Snapshot), + &settings.script_snapshot_path); + + command_line.GetOptionValue(FlagForSwitch(Switch::MainDartFile), + &settings.main_dart_file_path); + + command_line.GetOptionValue(FlagForSwitch(Switch::Packages), + &settings.packages_file_path); + + command_line.GetOptionValue(FlagForSwitch(Switch::AotSnapshotPath), + &settings.aot_snapshot_path); + + command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotData), + &settings.aot_vm_snapshot_data_filename); + + command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotInstructions), + &settings.aot_vm_snapshot_instr_filename); + + command_line.GetOptionValue(FlagForSwitch(Switch::AotIsolateSnapshotData), + &settings.aot_isolate_snapshot_data_filename); + + command_line.GetOptionValue( + FlagForSwitch(Switch::AotIsolateSnapshotInstructions), + &settings.aot_isolate_snapshot_instr_filename); + + command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath), + &settings.temp_directory_path); + + command_line.GetOptionValue(FlagForSwitch(Switch::ICUDataFilePath), + &settings.icu_data_path); + + settings.use_test_fonts = + command_line.HasOption(FlagForSwitch(Switch::UseTestFonts)); + + command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag); + std::string all_dart_flags; + if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags), + &all_dart_flags)) { + std::stringstream stream(all_dart_flags); + std::istream_iterator end; + for (std::istream_iterator it(stream); it != end; ++it) + settings.dart_flags.push_back(*it); + } + +#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE + settings.trace_skia = + command_line.HasOption(FlagForSwitch(Switch::TraceSkia)); +#endif + + return settings; +} + } // namespace shell diff --git a/shell/common/switches.h b/shell/common/switches.h index 91778a78e92cc..6b67b1f6a1567 100644 --- a/shell/common/switches.h +++ b/shell/common/switches.h @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/common/settings.h" +#include "lib/fxl/command_line.h" #include "lib/fxl/strings/string_view.h" #ifndef SHELL_COMMON_SWITCHES_H_ @@ -23,12 +25,29 @@ namespace shell { DEF_SWITCHES_START DEF_SWITCH(AotSharedLibraryPath, "aot-shared-library-path", "Path to the *.so.") -DEF_SWITCH(AotSnapshotPath, "aot-snapshot-path", "Path to the AOT snapshot.") -DEF_SWITCH(AotVmSnapshotData, "vm-snapshot-data", "") -DEF_SWITCH(AotVmSnapshotInstructions, "vm-snapshot-instr", "") -DEF_SWITCH(AotIsolateSnapshotData, "isolate-snapshot-data", "") -DEF_SWITCH(AotIsolateSnapshotInstructions, "isolate-snapshot-instr", "") +DEF_SWITCH(AotSnapshotPath, + "aot-snapshot-path", + "Path to the directory containing the four files specified by " + "AotVmSnapshotData, AotVmSnapshotInstructions, " + "AotVmSnapshotInstructions and AotIsolateSnapshotInstructions.") +DEF_SWITCH(AotVmSnapshotData, + "vm-snapshot-data", + "The VM snapshot data that will be memory mapped as read-only. " + "AotSnapshotPath must be present.") +DEF_SWITCH(AotVmSnapshotInstructions, + "vm-snapshot-instr", + "The VM instructions snapshot that will be memory mapped as read " + "and executable. AotSnapshotPath must be present.") +DEF_SWITCH(AotIsolateSnapshotData, + "isolate-snapshot-data", + "The isolate snapshot data that will be memory mapped as read-only. " + "AotSnapshotPath must be present.") +DEF_SWITCH(AotIsolateSnapshotInstructions, + "isolate-snapshot-instr", + "The isolate instructions snapshot that will be memory mapped as " + "read and executable. AotSnapshotPath must be present.") DEF_SWITCH(CacheDirPath, "cache-dir-path", "Path to the cache directory.") +DEF_SWITCH(ICUDataFilePath, "icu-data-file-path", "Path to the ICU data file.") DEF_SWITCH(DartFlags, "dart-flags", "Flags passed directly to the Dart VM without being interpreted " @@ -73,10 +92,6 @@ DEF_SWITCH(FlutterAssetsDir, DEF_SWITCH(Help, "help", "Display this help text.") DEF_SWITCH(LogTag, "log-tag", "Tag associated with log messages.") DEF_SWITCH(MainDartFile, "dart-main", "The path to the main Dart file.") -DEF_SWITCH(NonInteractive, - "non-interactive", - "Make the shell non-interactive. By default, the shell attempts " - "to setup a window and create an OpenGL context.") DEF_SWITCH(Packages, "packages", "Specify the path to the packages.") DEF_SWITCH(Snapshot, "snapshot-blob", "Specify the path to the snapshot blob") DEF_SWITCH(StartPaused, @@ -113,7 +128,9 @@ DEF_SWITCHES_END void PrintUsage(const std::string& executable_name); -const fxl::StringView FlagForSwitch(Switch sw); +const fxl::StringView FlagForSwitch(Switch swtch); + +blink::Settings SettingsFromCommandLine(const fxl::CommandLine& command_line); } // namespace shell diff --git a/shell/common/thread_host.cc b/shell/common/thread_host.cc new file mode 100644 index 0000000000000..f35594829d5d9 --- /dev/null +++ b/shell/common/thread_host.cc @@ -0,0 +1,38 @@ +// 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/shell/common/thread_host.h" + +namespace shell { + +ThreadHost::ThreadHost() = default; + +ThreadHost::ThreadHost(std::string name_prefix, uint64_t mask) { + if (mask & ThreadHost::Type::Platform) { + platform_thread = std::make_unique(name_prefix + ".platform"); + } + + if (mask & ThreadHost::Type::UI) { + ui_thread = std::make_unique(name_prefix + ".ui"); + } + + if (mask & ThreadHost::Type::GPU) { + gpu_thread = std::make_unique(name_prefix + ".gpu"); + } + + if (mask & ThreadHost::Type::IO) { + io_thread = std::make_unique(name_prefix + ".io"); + } +} + +ThreadHost::~ThreadHost() = default; + +void ThreadHost::Reset() { + platform_thread.reset(); + ui_thread.reset(); + gpu_thread.reset(); + io_thread.reset(); +} + +} // namespace shell diff --git a/shell/common/thread_host.h b/shell/common/thread_host.h new file mode 100644 index 0000000000000..a688aa6a06a85 --- /dev/null +++ b/shell/common/thread_host.h @@ -0,0 +1,43 @@ +// 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_SHELL_COMMON_THREAD_HOST_H_ +#define FLUTTER_SHELL_COMMON_THREAD_HOST_H_ + +#include + +#include "flutter/fml/thread.h" +#include "lib/fxl/macros.h" + +namespace shell { + +struct ThreadHost { + enum Type { + Platform = 1 << 0, + UI = 1 << 1, + GPU = 1 << 2, + IO = 1 << 3, + }; + + std::unique_ptr platform_thread; + std::unique_ptr ui_thread; + std::unique_ptr gpu_thread; + std::unique_ptr io_thread; + + ThreadHost(); + + ThreadHost(ThreadHost&&) = default; + + ThreadHost& operator=(ThreadHost&&) = default; + + ThreadHost(std::string name_prefix, uint64_t type_mask); + + ~ThreadHost(); + + void Reset(); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_COMMON_THREAD_HOST_H_ diff --git a/shell/common/tracing_controller.cc b/shell/common/tracing_controller.cc deleted file mode 100644 index 6fa8d9d5ee87f..0000000000000 --- a/shell/common/tracing_controller.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 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. - -#include "flutter/shell/common/tracing_controller.h" - -#include - -#include "flutter/common/threads.h" -#include "flutter/fml/trace_event.h" -#include "flutter/runtime/dart_init.h" -#include "flutter/shell/common/shell.h" -#include "lib/fxl/logging.h" -#include "third_party/dart/runtime/include/dart_tools_api.h" - -namespace shell { - -TracingController::TracingController() : tracing_active_(false) { - blink::SetEmbedderTracingCallbacks( - std::unique_ptr( - new blink::EmbedderTracingCallbacks([this]() { StartTracing(); }, - [this]() { StopTracing(); }))); -} - -TracingController::~TracingController() { - blink::SetEmbedderTracingCallbacks(nullptr); -} - -static void AddTraceMetadata() { - blink::Threads::Gpu()->PostTask([]() { Dart_SetThreadName("gpu_thread"); }); - blink::Threads::UI()->PostTask([]() { Dart_SetThreadName("ui_thread"); }); - blink::Threads::IO()->PostTask([]() { Dart_SetThreadName("io_thread"); }); - blink::Threads::Platform()->PostTask( - []() { Dart_SetThreadName("platform_thread"); }); -} - -void TracingController::StartTracing() { - if (tracing_active_) - return; - tracing_active_ = true; - AddTraceMetadata(); -} - -void TracingController::StopTracing() { - if (!tracing_active_) { - return; - } - tracing_active_ = false; -} - -} // namespace shell diff --git a/shell/common/tracing_controller.h b/shell/common/tracing_controller.h deleted file mode 100644 index 3f9e6f03ab14c..0000000000000 --- a/shell/common/tracing_controller.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015 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 SHELL_COMMON_TRACING_CONTROLLER_H_ -#define SHELL_COMMON_TRACING_CONTROLLER_H_ - -#include - -#include "lib/fxl/macros.h" - -namespace shell { - -class TracingController { - public: - TracingController(); - - ~TracingController(); - - void StartTracing(); - - void StopTracing(); - - bool tracing_active() const { return tracing_active_; } - - private: - bool tracing_active_; - - FXL_DISALLOW_COPY_AND_ASSIGN(TracingController); -}; - -} // namespace shell - -#endif // SHELL_COMMON_TRACING_CONTROLLER_H_ diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index 5acc235b1f68d..ba2f21c389c11 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -4,8 +4,45 @@ #include "flutter/shell/common/vsync_waiter.h" +#include "flutter/fml/task_runner.h" +#include "flutter/fml/trace_event.h" + namespace shell { +VsyncWaiter::VsyncWaiter(blink::TaskRunners task_runners) + : task_runners_(std::move(task_runners)) {} + VsyncWaiter::~VsyncWaiter() = default; +void VsyncWaiter::AsyncWaitForVsync(Callback callback) { + { + std::lock_guard lock(callback_mutex_); + callback_ = std::move(callback); + } + AwaitVSync(); +} + +void VsyncWaiter::FireCallback(fxl::TimePoint frame_start_time, + fxl::TimePoint frame_target_time) { + Callback callback; + + { + std::lock_guard lock(callback_mutex_); + callback = std::move(callback_); + } + + if (!callback) { + return; + } + + task_runners_.GetUITaskRunner()->PostTask( + [callback, frame_start_time, frame_target_time]() { + // Note: The tag name must be "VSYNC" (it is special) so that the + // "Highlight + // Vsync" checkbox in the timeline can be enabled. + TRACE_EVENT0("flutter", "VSYNC"); + callback(frame_start_time, frame_target_time); + }); +} + } // namespace shell diff --git a/shell/common/vsync_waiter.h b/shell/common/vsync_waiter.h index 77319ed8b6966..82231fdf4f853 100644 --- a/shell/common/vsync_waiter.h +++ b/shell/common/vsync_waiter.h @@ -6,7 +6,10 @@ #define FLUTTER_SHELL_COMMON_VSYNC_WAITER_H_ #include +#include +#include +#include "flutter/common/task_runners.h" #include "lib/fxl/time/time_point.h" namespace shell { @@ -16,9 +19,23 @@ class VsyncWaiter { using Callback = std::function; - virtual void AsyncWaitForVsync(Callback callback) = 0; - virtual ~VsyncWaiter(); + + void AsyncWaitForVsync(Callback callback); + + protected: + const blink::TaskRunners task_runners_; + std::mutex callback_mutex_; + Callback callback_; + + VsyncWaiter(blink::TaskRunners task_runners); + + virtual void AwaitVSync() = 0; + + void FireCallback(fxl::TimePoint frame_start_time, + fxl::TimePoint frame_target_time); + + FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter); }; } // namespace shell diff --git a/shell/common/vsync_waiter_fallback.cc b/shell/common/vsync_waiter_fallback.cc index 01c86cdedc6aa..bcf061bb7615f 100644 --- a/shell/common/vsync_waiter_fallback.cc +++ b/shell/common/vsync_waiter_fallback.cc @@ -4,7 +4,6 @@ #include "flutter/shell/common/vsync_waiter_fallback.h" -#include "flutter/common/threads.h" #include "lib/fxl/logging.h" namespace shell { @@ -21,28 +20,25 @@ fxl::TimePoint SnapToNextTick(fxl::TimePoint value, } // namespace -VsyncWaiterFallback::VsyncWaiterFallback() - : phase_(fxl::TimePoint::Now()), weak_factory_(this) {} +VsyncWaiterFallback::VsyncWaiterFallback(blink::TaskRunners task_runners) + : VsyncWaiter(std::move(task_runners)), + phase_(fxl::TimePoint::Now()), + weak_factory_(this) {} VsyncWaiterFallback::~VsyncWaiterFallback() = default; constexpr fxl::TimeDelta interval = fxl::TimeDelta::FromSecondsF(1.0 / 60.0); -void VsyncWaiterFallback::AsyncWaitForVsync(Callback callback) { - FXL_DCHECK(!callback_); - callback_ = std::move(callback); - +void VsyncWaiterFallback::AwaitVSync() { fxl::TimePoint now = fxl::TimePoint::Now(); fxl::TimePoint next = SnapToNextTick(now, phase_, interval); - blink::Threads::UI()->PostDelayedTask( + task_runners_.GetUITaskRunner()->PostDelayedTask( [self = weak_factory_.GetWeakPtr()] { - if (!self) - return; - fxl::TimePoint frame_time = fxl::TimePoint::Now(); - Callback callback = std::move(self->callback_); - self->callback_ = Callback(); - callback(frame_time, frame_time + interval); + if (self) { + const auto frame_time = fxl::TimePoint::Now(); + self->FireCallback(frame_time, frame_time + interval); + } }, next - now); } diff --git a/shell/common/vsync_waiter_fallback.h b/shell/common/vsync_waiter_fallback.h index bfb7e118b1330..d3cc8faaf6ce7 100644 --- a/shell/common/vsync_waiter_fallback.h +++ b/shell/common/vsync_waiter_fallback.h @@ -5,25 +5,24 @@ #ifndef FLUTTER_SHELL_COMMON_VSYNC_WAITER_FALLBACK_H_ #define FLUTTER_SHELL_COMMON_VSYNC_WAITER_FALLBACK_H_ -#include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/vsync_waiter.h" #include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" #include "lib/fxl/time/time_point.h" namespace shell { -class VsyncWaiterFallback : public VsyncWaiter { +class VsyncWaiterFallback final : public VsyncWaiter { public: - VsyncWaiterFallback(); - ~VsyncWaiterFallback() override; + VsyncWaiterFallback(blink::TaskRunners task_runners); - void AsyncWaitForVsync(Callback callback) override; + ~VsyncWaiterFallback() override; private: fxl::TimePoint phase_; - Callback callback_; + fxl::WeakPtrFactory weak_factory_; - fml::WeakPtrFactory weak_factory_; + void AwaitVSync() override; FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterFallback); }; diff --git a/shell/gpu/BUILD.gn b/shell/gpu/BUILD.gn index c050e120b0a10..cd093e1238f7f 100644 --- a/shell/gpu/BUILD.gn +++ b/shell/gpu/BUILD.gn @@ -6,14 +6,17 @@ import("$flutter_root/shell/config.gni") source_set("gpu") { sources = [ - "gpu_rasterizer.cc", - "gpu_rasterizer.h", - "gpu_surface_gl.cc", - "gpu_surface_gl.h", "gpu_surface_software.cc", "gpu_surface_software.h", ] + if (!is_fuchsia) { + sources += [ + "gpu_surface_gl.cc", + "gpu_surface_gl.h", + ] + } + if (shell_enable_vulkan) { sources += [ "gpu_surface_vulkan.cc", diff --git a/shell/gpu/gpu_rasterizer.cc b/shell/gpu/gpu_rasterizer.cc deleted file mode 100644 index 3424f989b3205..0000000000000 --- a/shell/gpu/gpu_rasterizer.cc +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2015 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. - -#include "gpu_rasterizer.h" - -#include -#include - -#include "flutter/common/threads.h" -#include "flutter/glue/trace_event.h" -#include "flutter/shell/common/picture_serializer.h" -#include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/shell.h" -#include "third_party/skia/include/core/SkPicture.h" - -namespace shell { - -GPURasterizer::GPURasterizer(std::unique_ptr info) - : compositor_context_(std::move(info)), weak_factory_(this) {} - -GPURasterizer::~GPURasterizer() = default; - -fml::WeakPtr GPURasterizer::GetWeakRasterizerPtr() { - return weak_factory_.GetWeakPtr(); -} - -void GPURasterizer::Setup(std::unique_ptr surface, - fxl::Closure continuation, - fxl::AutoResetWaitableEvent* setup_completion_event) { - surface_ = std::move(surface); - compositor_context_.OnGrContextCreated(); - - continuation(); - - setup_completion_event->Signal(); -} - -void GPURasterizer::Clear(SkColor color, const SkISize& size) { - if (surface_ == nullptr) { - return; - } - - auto frame = surface_->AcquireFrame(size); - - if (frame == nullptr) { - return; - } - - SkCanvas* canvas = frame->SkiaCanvas(); - - if (canvas == nullptr) { - return; - } - - canvas->clear(color); - - frame->Submit(); -} - -void GPURasterizer::Teardown( - fxl::AutoResetWaitableEvent* teardown_completion_event) { - compositor_context_.OnGrContextDestroyed(); - if (surface_) { - surface_.reset(); - } - last_layer_tree_.reset(); - teardown_completion_event->Signal(); -} - -flow::LayerTree* GPURasterizer::GetLastLayerTree() { - return last_layer_tree_.get(); -} - -void GPURasterizer::DrawLastLayerTree() { - if (!last_layer_tree_ || !surface_) { - return; - } - DrawToSurface(*last_layer_tree_); -} - -flow::TextureRegistry& GPURasterizer::GetTextureRegistry() { - return compositor_context_.texture_registry(); -} - -void GPURasterizer::Draw( - fxl::RefPtr> pipeline) { - TRACE_EVENT0("flutter", "GPURasterizer::Draw"); - - flutter::Pipeline::Consumer consumer = - std::bind(&GPURasterizer::DoDraw, this, std::placeholders::_1); - - // Consume as many pipeline items as possible. But yield the event loop - // between successive tries. - switch (pipeline->Consume(consumer)) { - case flutter::PipelineConsumeResult::MoreAvailable: { - auto weak_this = weak_factory_.GetWeakPtr(); - blink::Threads::Gpu()->PostTask([weak_this, pipeline]() { - if (weak_this) { - weak_this->Draw(pipeline); - } - }); - break; - } - default: - break; - } -} - -void GPURasterizer::DoDraw(std::unique_ptr layer_tree) { - if (!layer_tree || !surface_) { - return; - } - - // There is no way for the compositor to know how long the layer tree - // construction took. Fortunately, the layer tree does. Grab that time - // for instrumentation. - compositor_context_.engine_time().SetLapTime(layer_tree->construction_time()); - - DrawToSurface(*layer_tree); - - NotifyNextFrameOnce(); - - last_layer_tree_ = std::move(layer_tree); -} - -void GPURasterizer::DrawToSurface(flow::LayerTree& layer_tree) { - auto frame = surface_->AcquireFrame(layer_tree.frame_size()); - - if (frame == nullptr) { - return; - } - - auto canvas = frame->SkiaCanvas(); - - if (canvas == nullptr) { - return; - } - - auto compositor_frame = - compositor_context_.AcquireFrame(surface_->GetContext(), canvas); - - canvas->clear(SK_ColorBLACK); - - layer_tree.Raster(compositor_frame); - - frame->Submit(); -} - -void GPURasterizer::AddNextFrameCallback(fxl::Closure nextFrameCallback) { - nextFrameCallback_ = nextFrameCallback; -} - -void GPURasterizer::NotifyNextFrameOnce() { - if (nextFrameCallback_) { - blink::Threads::Platform()->PostTask([callback = nextFrameCallback_] { - TRACE_EVENT0("flutter", "GPURasterizer::NotifyNextFrameOnce"); - callback(); - }); - nextFrameCallback_ = nullptr; - } -} - -void GPURasterizer::SetTextureRegistry(flow::TextureRegistry* textureRegistry) { - compositor_context_.SetTextureRegistry(textureRegistry); -} - -} // namespace shell diff --git a/shell/gpu/gpu_rasterizer.h b/shell/gpu/gpu_rasterizer.h deleted file mode 100644 index ad16ee2c47989..0000000000000 --- a/shell/gpu/gpu_rasterizer.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2015 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 SHELL_GPU_DIRECT_GPU_RASTERIZER_H_ -#define SHELL_GPU_DIRECT_GPU_RASTERIZER_H_ - -#include "flutter/flow/compositor_context.h" -#include "flutter/shell/common/rasterizer.h" -#include "lib/fxl/memory/weak_ptr.h" -#include "lib/fxl/synchronization/waitable_event.h" - -namespace shell { - -class Surface; - -class GPURasterizer : public Rasterizer { - public: - GPURasterizer(std::unique_ptr info); - - ~GPURasterizer() override; - - void Setup(std::unique_ptr surface, - fxl::Closure continuation, - fxl::AutoResetWaitableEvent* setup_completion_event) override; - - void Clear(SkColor color, const SkISize& size) override; - - void Teardown( - fxl::AutoResetWaitableEvent* teardown_completion_event) override; - - fml::WeakPtr GetWeakRasterizerPtr() override; - - flow::LayerTree* GetLastLayerTree() override; - - void DrawLastLayerTree() override; - - flow::TextureRegistry& GetTextureRegistry() override; - - void Draw(fxl::RefPtr> pipeline) override; - - // Set a callback to be called once when the next frame is drawn. - void AddNextFrameCallback(fxl::Closure nextFrameCallback) override; - - void SetTextureRegistry(flow::TextureRegistry* textureRegistry) override; - - private: - std::unique_ptr surface_; - flow::CompositorContext compositor_context_; - std::unique_ptr last_layer_tree_; - // A closure to be called when the underlaying surface presents a frame the - // next time. NULL if there is no callback or the callback was set back to - // NULL after being called. - fxl::Closure nextFrameCallback_; - fml::WeakPtrFactory weak_factory_; - - void DoDraw(std::unique_ptr layer_tree); - - void DrawToSurface(flow::LayerTree& layer_tree); - - void NotifyNextFrameOnce(); - - FXL_DISALLOW_COPY_AND_ASSIGN(GPURasterizer); -}; - -} // namespace shell - -#endif // SHELL_GPU_DIRECT_GPU_RASTERIZER_H_ diff --git a/shell/gpu/gpu_surface_gl.cc b/shell/gpu/gpu_surface_gl.cc index 331fd188a9ed3..284a10e413b46 100644 --- a/shell/gpu/gpu_surface_gl.cc +++ b/shell/gpu/gpu_surface_gl.cc @@ -72,6 +72,8 @@ GPUSurfaceGL::~GPUSurfaceGL() { return; } + GetCompositorContext().OnGrContextDestroyed(); + onscreen_surface_ = nullptr; context_->releaseResourcesAndAbandonContext(); context_ = nullptr; @@ -210,12 +212,11 @@ std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { return nullptr; } - auto weak_this = weak_factory_.GetWeakPtr(); - - SurfaceFrame::SubmitCallback submit_callback = - [weak_this](const SurfaceFrame& surface_frame, SkCanvas* canvas) { - return weak_this ? weak_this->PresentSurface(canvas) : false; - }; + SurfaceFrame::SubmitCallback submit_callback = [weak = weak_factory_ + .GetWeakPtr()]( + const SurfaceFrame& surface_frame, SkCanvas* canvas) { + return weak ? weak->PresentSurface(canvas) : false; + }; return std::make_unique(surface, submit_callback); } diff --git a/shell/gpu/gpu_surface_gl.h b/shell/gpu/gpu_surface_gl.h index 5cf092dae66c5..abc9f46aee297 100644 --- a/shell/gpu/gpu_surface_gl.h +++ b/shell/gpu/gpu_surface_gl.h @@ -5,10 +5,9 @@ #ifndef SHELL_GPU_GPU_SURFACE_GL_H_ #define SHELL_GPU_GPU_SURFACE_GL_H_ -#include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/surface.h" -#include "flutter/synchronization/debug_thread_checker.h" #include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" #include "third_party/skia/include/gpu/GrContext.h" namespace shell { @@ -44,7 +43,7 @@ class GPUSurfaceGL : public Surface { sk_sp onscreen_surface_; sk_sp offscreen_surface_; bool valid_ = false; - fml::WeakPtrFactory weak_factory_; + fxl::WeakPtrFactory weak_factory_; bool CreateOrUpdateSurfaces(const SkISize& size); diff --git a/shell/gpu/gpu_surface_software.cc b/shell/gpu/gpu_surface_software.cc index e340e605652dd..ea8c827b22405 100644 --- a/shell/gpu/gpu_surface_software.cc +++ b/shell/gpu/gpu_surface_software.cc @@ -18,20 +18,13 @@ bool GPUSurfaceSoftware::IsValid() { return delegate_ != nullptr; } -bool GPUSurfaceSoftware::SupportsScaling() const { - return true; -} - std::unique_ptr GPUSurfaceSoftware::AcquireFrame( const SkISize& logical_size) { if (!IsValid()) { return nullptr; } - // Check if we need to support surface scaling. - const auto scale = SupportsScaling() ? GetScale() : 1.0; - const auto size = SkISize::Make(logical_size.width() * scale, - logical_size.height() * scale); + const auto size = SkISize::Make(logical_size.width(), logical_size.height()); sk_sp backing_store = delegate_->AcquireBackingStore(size); @@ -48,12 +41,10 @@ std::unique_ptr GPUSurfaceSoftware::AcquireFrame( // irrespective of surface scaling. SkCanvas* canvas = backing_store->getCanvas(); canvas->resetMatrix(); - canvas->scale(scale, scale); - SurfaceFrame::SubmitCallback - on_submit = [self = weak_factory_.GetWeakPtr()]( - const SurfaceFrame& surface_frame, SkCanvas* canvas) - ->bool { + SurfaceFrame::SubmitCallback on_submit = + [self = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame, + SkCanvas* canvas) -> bool { // If the surface itself went away, there is nothing more to do. if (!self || !self->IsValid() || canvas == nullptr) { return false; diff --git a/shell/gpu/gpu_surface_software.h b/shell/gpu/gpu_surface_software.h index f7312153db8bc..238754f312b80 100644 --- a/shell/gpu/gpu_surface_software.h +++ b/shell/gpu/gpu_surface_software.h @@ -5,9 +5,9 @@ #ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_SOFTWARE_H_ #define FLUTTER_SHELL_GPU_GPU_SURFACE_SOFTWARE_H_ -#include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/surface.h" #include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" #include "third_party/skia/include/core/SkSurface.h" namespace shell { @@ -30,12 +30,9 @@ class GPUSurfaceSoftware : public Surface { GrContext* GetContext() override; - bool SupportsScaling() const override; - private: GPUSurfaceSoftwareDelegate* delegate_; - - fml::WeakPtrFactory weak_factory_; + fxl::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceSoftware); }; diff --git a/shell/gpu/gpu_surface_vulkan.h b/shell/gpu/gpu_surface_vulkan.h index eafed43a6296d..f1e25fbe987b8 100644 --- a/shell/gpu/gpu_surface_vulkan.h +++ b/shell/gpu/gpu_surface_vulkan.h @@ -6,11 +6,12 @@ #define SHELL_GPU_GPU_SURFACE_VULKAN_H_ #include -#include "flutter/fml/memory/weak_ptr.h" + #include "flutter/shell/common/surface.h" #include "flutter/vulkan/vulkan_native_surface.h" #include "flutter/vulkan/vulkan_window.h" #include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" namespace shell { @@ -29,7 +30,7 @@ class GPUSurfaceVulkan : public Surface { private: vulkan::VulkanWindow window_; - fml::WeakPtrFactory weak_factory_; + fxl::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceVulkan); }; diff --git a/shell/platform/BUILD.gn b/shell/platform/BUILD.gn index 4b1e1a9e0bfeb..ae3b1003f22fe 100644 --- a/shell/platform/BUILD.gn +++ b/shell/platform/BUILD.gn @@ -13,13 +13,11 @@ group("platform") { ] } else if (is_linux) { deps = [ - "linux", "embedder", ] } else if (is_win) { - deps = [ - "win" - ] + # There is no platform target on windows. Instead, only a tester is used. + deps = [] } else { assert(false, "Unknown/Unsupported platform.") } diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index d9744ad890caa..129c877faed0f 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -17,21 +17,25 @@ shared_library("flutter_shell_native") { "android_context_gl.h", "android_environment_gl.cc", "android_environment_gl.h", - "android_external_texture_gl.h", "android_external_texture_gl.cc", + "android_external_texture_gl.h", "android_native_window.cc", "android_native_window.h", + "android_shell_holder.cc", + "android_shell_holder.h", "android_surface.cc", "android_surface.h", "android_surface_gl.cc", "android_surface_gl.h", - "android_surface_software.h", "android_surface_software.cc", - "apk_asset_provider.h", + "android_surface_software.h", "apk_asset_provider.cc", + "apk_asset_provider.h", "flutter_main.cc", "flutter_main.h", "library_loader.cc", + "platform_message_response_android.cc", + "platform_message_response_android.h", "platform_view_android.cc", "platform_view_android.h", "platform_view_android_jni.cc", @@ -41,10 +45,10 @@ shared_library("flutter_shell_native") { ] deps = [ + "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", "$flutter_root/fml", - "$flutter_root/assets", "$flutter_root/lib/ui", "$flutter_root/runtime", "$flutter_root/shell/common", @@ -59,9 +63,7 @@ shared_library("flutter_shell_native") { deps += [ "//third_party/dart/runtime:libdart_precompiled_runtime" ] } - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] defines = [] diff --git a/shell/platform/android/android_context_gl.cc b/shell/platform/android/android_context_gl.cc index f54629f8644b9..6338dc96908e1 100644 --- a/shell/platform/android/android_context_gl.cc +++ b/shell/platform/android/android_context_gl.cc @@ -3,9 +3,13 @@ // found in the LICENSE file. #include "flutter/shell/platform/android/android_context_gl.h" + #include + #include +#include "flutter/fml/trace_event.h" + namespace shell { template @@ -65,19 +69,17 @@ static EGLResult CreateContext(EGLDisplay display, return {context != EGL_NO_CONTEXT, context}; } -static EGLResult ChooseEGLConfiguration( - EGLDisplay display, - PlatformView::SurfaceConfig config) { +static EGLResult ChooseEGLConfiguration(EGLDisplay display) { EGLint attributes[] = { // clang-format off EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, config.red_bits, - EGL_GREEN_SIZE, config.green_bits, - EGL_BLUE_SIZE, config.blue_bits, - EGL_ALPHA_SIZE, config.alpha_bits, - EGL_DEPTH_SIZE, config.depth_bits, - EGL_STENCIL_SIZE, config.stencil_bits, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, EGL_NONE, // termination sentinel // clang-format on }; @@ -142,7 +144,6 @@ bool AndroidContextGL::CreatePBufferSurface() { } AndroidContextGL::AndroidContextGL(fxl::RefPtr env, - PlatformView::SurfaceConfig config, const AndroidContextGL* share_context) : environment_(env), window_(nullptr), @@ -158,8 +159,7 @@ AndroidContextGL::AndroidContextGL(fxl::RefPtr env, // Choose a valid configuration. - std::tie(success, config_) = - ChooseEGLConfiguration(environment_->Display(), config); + std::tie(success, config_) = ChooseEGLConfiguration(environment_->Display()); if (!success) { FXL_LOG(ERROR) << "Could not choose an EGL configuration."; diff --git a/shell/platform/android/android_context_gl.h b/shell/platform/android/android_context_gl.h index 207f621c66bd1..b29851b34564d 100644 --- a/shell/platform/android/android_context_gl.h +++ b/shell/platform/android/android_context_gl.h @@ -44,7 +44,6 @@ class AndroidContextGL : public fxl::RefCountedThreadSafe { bool valid_; AndroidContextGL(fxl::RefPtr env, - PlatformView::SurfaceConfig config, const AndroidContextGL* share_context = nullptr); ~AndroidContextGL(); diff --git a/shell/platform/android/android_external_texture_gl.cc b/shell/platform/android/android_external_texture_gl.cc index 02a40c22474a1..35db9cbbfdb95 100644 --- a/shell/platform/android/android_external_texture_gl.cc +++ b/shell/platform/android/android_external_texture_gl.cc @@ -5,7 +5,7 @@ #include "flutter/shell/platform/android/android_external_texture_gl.h" #include -#include "flutter/common/threads.h" + #include "flutter/shell/platform/android/platform_view_android_jni.h" #include "third_party/skia/include/gpu/GrTexture.h" @@ -19,17 +19,14 @@ AndroidExternalTextureGL::AndroidExternalTextureGL( AndroidExternalTextureGL::~AndroidExternalTextureGL() = default; void AndroidExternalTextureGL::OnGrContextCreated() { - ASSERT_IS_GPU_THREAD; state_ = AttachmentState::uninitialized; } void AndroidExternalTextureGL::MarkNewFrameAvailable() { - ASSERT_IS_GPU_THREAD; new_frame_ready_ = true; } void AndroidExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds) { - ASSERT_IS_GPU_THREAD; if (state_ == AttachmentState::detached) { return; } @@ -42,7 +39,8 @@ void AndroidExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds) { Update(); new_frame_ready_ = false; } - GrGLTextureInfo textureInfo = {GL_TEXTURE_EXTERNAL_OES, texture_name_, GL_RGBA8_OES}; + GrGLTextureInfo textureInfo = {GL_TEXTURE_EXTERNAL_OES, texture_name_, + GL_RGBA8_OES}; GrBackendTexture backendTexture(1, 1, GrMipMapped::kNo, textureInfo); sk_sp image = SkImage::MakeFromTexture( canvas.getGrContext(), backendTexture, kTopLeft_GrSurfaceOrigin, @@ -82,7 +80,6 @@ void AndroidExternalTextureGL::UpdateTransform() { } void AndroidExternalTextureGL::OnGrContextDestroyed() { - ASSERT_IS_GPU_THREAD; if (state_ == AttachmentState::attached) { Detach(); } diff --git a/shell/platform/android/android_external_texture_gl.h b/shell/platform/android/android_external_texture_gl.h index df890b91c827f..67d6541d964c2 100644 --- a/shell/platform/android/android_external_texture_gl.h +++ b/shell/platform/android/android_external_texture_gl.h @@ -25,8 +25,7 @@ class AndroidExternalTextureGL : public flow::Texture { virtual void OnGrContextDestroyed() override; - // Called on GPU thread. - void MarkNewFrameAvailable(); + void MarkNewFrameAvailable() override; private: void Attach(jint textureName); diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc new file mode 100644 index 0000000000000..7dc454f1fb74a --- /dev/null +++ b/shell/platform/android/android_shell_holder.cc @@ -0,0 +1,169 @@ +// 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. + +#define FML_USED_ON_EMBEDDER + +#include "flutter/shell/platform/android/android_shell_holder.h" + +#include +#include + +#include +#include +#include + +#include "flutter/fml/message_loop.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/platform/android/platform_view_android.h" +#include "lib/fxl/functional/make_copyable.h" + +namespace shell { + +AndroidShellHolder::AndroidShellHolder( + blink::Settings settings, + fml::jni::JavaObjectWeakGlobalRef java_object) + : settings_(std::move(settings)), java_object_(java_object) { + static size_t shell_count = 1; + auto thread_label = std::to_string(shell_count++); + + thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | + ThreadHost::Type::IO}; + + fml::WeakPtr weak_platform_view; + Shell::CreateCallback on_create_platform_view = + [java_object, &weak_platform_view](Shell& shell) { + auto platform_view_android = std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + java_object, // java object handle for JNI interop + shell.GetSettings() + .enable_software_rendering // use software rendering + ); + weak_platform_view = platform_view_android->GetWeakPtr(); + return platform_view_android; + }; + + Shell::CreateCallback on_create_rasterizer = [](Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }; + + // The current thread will be used as the platform thread. Ensure that the + // message loop is initialized. + fml::MessageLoop::EnsureInitializedForCurrentThread(); + + blink::TaskRunners task_runners( + thread_label, // label + fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform + thread_host_.gpu_thread->GetTaskRunner(), // gpu + thread_host_.ui_thread->GetTaskRunner(), // ui + thread_host_.io_thread->GetTaskRunner() // io + ); + + shell_ = + Shell::Create(task_runners, // task runners + settings_, // settings + on_create_platform_view, // platform view create callback + on_create_rasterizer // rasterizer create callback + ); + + platform_view_ = weak_platform_view; + FXL_DCHECK(platform_view_); + + is_valid_ = shell_ != nullptr; + + if (is_valid_) { + task_runners.GetGPUTaskRunner()->PostTask( + []() { ::setpriority(PRIO_PROCESS, gettid(), -2); }); + task_runners.GetUITaskRunner()->PostTask( + []() { ::setpriority(PRIO_PROCESS, gettid(), -1); }); + } +} + +AndroidShellHolder::~AndroidShellHolder() = default; + +bool AndroidShellHolder::IsValid() const { + return is_valid_; +} + +const blink::Settings& AndroidShellHolder::GetSettings() const { + return settings_; +} + +void AndroidShellHolder::Launch(RunConfiguration config) { + if (!IsValid()) { + return; + } + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask( + fxl::MakeCopyable([engine = shell_->GetEngine(), // + config = std::move(config) // + ]() mutable { + if (engine) { + if (!engine->Run(std::move(config))) { + FXL_LOG(ERROR) << "Could not launch engine in configuration."; + } + } + })); +} + +void AndroidShellHolder::SetViewportMetrics( + const blink::ViewportMetrics& metrics) { + if (!IsValid()) { + return; + } + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask( + [engine = shell_->GetEngine(), metrics]() { + if (engine) { + engine->SetViewportMetrics(metrics); + } + }); +} + +void AndroidShellHolder::DispatchPointerDataPacket( + std::unique_ptr packet) { + if (!IsValid()) { + return; + } + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask(fxl::MakeCopyable( + [engine = shell_->GetEngine(), packet = std::move(packet)] { + if (engine) { + engine->DispatchPointerDataPacket(*packet); + } + })); +} + +Rasterizer::Screenshot AndroidShellHolder::Screenshot( + Rasterizer::ScreenshotType type, + bool base64_encode) { + if (!IsValid()) { + return {nullptr, SkISize::MakeEmpty()}; + } + return shell_->Screenshot(type, base64_encode); +} + +fml::WeakPtr AndroidShellHolder::GetPlatformView() { + FXL_DCHECK(platform_view_); + return platform_view_; +} + +void AndroidShellHolder::UpdateAssetManager( + fxl::RefPtr asset_manager) { + if (!IsValid() || !asset_manager) { + return; + } + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask( + [engine = shell_->GetEngine(), + asset_manager = std::move(asset_manager)]() { + if (engine) { + if (!engine->UpdateAssetManager(std::move(asset_manager))) { + FXL_DLOG(ERROR) << "Could not update asset asset manager."; + } + } + }); +} + +} // namespace shell diff --git a/shell/platform/android/android_shell_holder.h b/shell/platform/android/android_shell_holder.h new file mode 100644 index 0000000000000..e0905f0f9e42e --- /dev/null +++ b/shell/platform/android/android_shell_holder.h @@ -0,0 +1,59 @@ +// 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_SHELL_PLATFORM_ANDROID_ANDROID_SHELL_HOLDER_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SHELL_HOLDER_H_ + +#include + +#include "flutter/fml/platform/android/jni_weak_ref.h" +#include "flutter/lib/ui/window/viewport_metrics.h" +#include "flutter/shell/common/run_configuration.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/android/platform_view_android.h" +#include "lib/fxl/files/unique_fd.h" +#include "lib/fxl/macros.h" + +namespace shell { + +class AndroidShellHolder { + public: + AndroidShellHolder(blink::Settings settings, + fml::jni::JavaObjectWeakGlobalRef java_object); + + ~AndroidShellHolder(); + + bool IsValid() const; + + void Launch(RunConfiguration configuration); + + void SetViewportMetrics(const blink::ViewportMetrics& metrics); + + void DispatchPointerDataPacket( + std::unique_ptr packet); + + const blink::Settings& GetSettings() const; + + fml::WeakPtr GetPlatformView(); + + Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, + bool base64_encode); + + void UpdateAssetManager(fxl::RefPtr asset_manager); + + private: + const blink::Settings settings_; + const fml::jni::JavaObjectWeakGlobalRef java_object_; + fml::WeakPtr platform_view_; + ThreadHost thread_host_; + std::unique_ptr shell_; + bool is_valid_ = false; + + FXL_DISALLOW_COPY_AND_ASSIGN(AndroidShellHolder); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SHELL_HOLDER_H_ diff --git a/shell/platform/android/android_surface.cc b/shell/platform/android/android_surface.cc index 4dd08609da370..a8b41bacbf7c5 100644 --- a/shell/platform/android/android_surface.cc +++ b/shell/platform/android/android_surface.cc @@ -4,8 +4,32 @@ #include "flutter/shell/platform/android/android_surface.h" +#include + +#include "flutter/shell/platform/android/android_surface_gl.h" +#include "flutter/shell/platform/android/android_surface_software.h" +#if SHELL_ENABLE_VULKAN +#include "flutter/shell/platform/android/android_surface_vulkan.h" +#endif // SHELL_ENABLE_VULKAN + namespace shell { +std::unique_ptr AndroidSurface::Create( + bool use_software_rendering) { + if (use_software_rendering) { + auto software_surface = std::make_unique(); + return software_surface->IsValid() ? std::move(software_surface) : nullptr; + } +#if SHELL_ENABLE_VULKAN + auto vulkan_surface = std::make_unique(); + return vulkan_surface->IsValid() ? std::move(vulkan_surface) : nullptr; +#else // SHELL_ENABLE_VULKAN + auto gl_surface = std::make_unique(); + return gl_surface->IsOffscreenContextValid() ? std::move(gl_surface) + : nullptr; +#endif // SHELL_ENABLE_VULKAN +} + AndroidSurface::~AndroidSurface() = default; } // namespace shell diff --git a/shell/platform/android/android_surface.h b/shell/platform/android/android_surface.h index 2425a61e20707..858b07eb45d9f 100644 --- a/shell/platform/android/android_surface.h +++ b/shell/platform/android/android_surface.h @@ -19,6 +19,8 @@ namespace shell { class AndroidSurface { public: + static std::unique_ptr Create(bool use_software_rendering); + virtual ~AndroidSurface(); virtual bool IsValid() const = 0; @@ -27,14 +29,11 @@ class AndroidSurface { virtual std::unique_ptr CreateGPUSurface() = 0; - virtual SkISize OnScreenSurfaceSize() const = 0; - virtual bool OnScreenSurfaceResize(const SkISize& size) const = 0; virtual bool ResourceContextMakeCurrent() = 0; - virtual bool SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config = {}) = 0; + virtual bool SetNativeWindow(fxl::RefPtr window) = 0; }; } // namespace shell diff --git a/shell/platform/android/android_surface_gl.cc b/shell/platform/android/android_surface_gl.cc index f30ac1272b043..274b652a97b74 100644 --- a/shell/platform/android/android_surface_gl.cc +++ b/shell/platform/android/android_surface_gl.cc @@ -6,14 +6,12 @@ #include -#include "flutter/common/threads.h" #include "lib/fxl/logging.h" #include "lib/fxl/memory/ref_ptr.h" namespace shell { -static fxl::RefPtr GlobalResourceLoadingContext( - PlatformView::SurfaceConfig offscreen_config) { +static fxl::RefPtr GlobalResourceLoadingContext() { // AndroidSurfaceGL instances are only ever created on the platform thread. So // there is no need to lock here. @@ -29,11 +27,7 @@ static fxl::RefPtr GlobalResourceLoadingContext( return nullptr; } - // TODO(chinmaygarde): We should check that the configurations are stable - // across multiple invocations. - - auto context = - fxl::MakeRefCounted(environment, offscreen_config); + auto context = fxl::MakeRefCounted(environment); if (!context->IsValid()) { return nullptr; @@ -43,10 +37,9 @@ static fxl::RefPtr GlobalResourceLoadingContext( return global_context; } -AndroidSurfaceGL::AndroidSurfaceGL( - PlatformView::SurfaceConfig offscreen_config) { +AndroidSurfaceGL::AndroidSurfaceGL() { // Acquire the offscreen context. - offscreen_context_ = GlobalResourceLoadingContext(offscreen_config); + offscreen_context_ = GlobalResourceLoadingContext(); if (!offscreen_context_ || !offscreen_context_->IsValid()) { offscreen_context_ = nullptr; @@ -60,14 +53,9 @@ bool AndroidSurfaceGL::IsOffscreenContextValid() const { } void AndroidSurfaceGL::TeardownOnScreenContext() { - fxl::AutoResetWaitableEvent latch; - blink::Threads::Gpu()->PostTask([this, &latch]() { - if (IsValid()) { - GLContextClearCurrent(); - } - latch.Signal(); - }); - latch.Wait(); + if (onscreen_context_) { + onscreen_context_->ClearCurrent(); + } onscreen_context_ = nullptr; } @@ -84,11 +72,6 @@ std::unique_ptr AndroidSurfaceGL::CreateGPUSurface() { return surface->IsValid() ? std::move(surface) : nullptr; } -SkISize AndroidSurfaceGL::OnScreenSurfaceSize() const { - FXL_DCHECK(onscreen_context_ && onscreen_context_->IsValid()); - return onscreen_context_->GetSize(); -} - bool AndroidSurfaceGL::OnScreenSurfaceResize(const SkISize& size) const { FXL_DCHECK(onscreen_context_ && onscreen_context_->IsValid()); return onscreen_context_->Resize(size); @@ -99,8 +82,8 @@ bool AndroidSurfaceGL::ResourceContextMakeCurrent() { return offscreen_context_->MakeCurrent(); } -bool AndroidSurfaceGL::SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config) { +bool AndroidSurfaceGL::SetNativeWindow( + fxl::RefPtr window) { // In any case, we want to get rid of our current onscreen context. onscreen_context_ = nullptr; @@ -112,7 +95,7 @@ bool AndroidSurfaceGL::SetNativeWindow(fxl::RefPtr window, // Create the onscreen context. onscreen_context_ = fxl::MakeRefCounted( - offscreen_context_->Environment(), config, + offscreen_context_->Environment(), offscreen_context_.get() /* sharegroup */); if (!onscreen_context_->IsValid()) { diff --git a/shell/platform/android/android_surface_gl.h b/shell/platform/android/android_surface_gl.h index 08aee081c8266..e26f2bf50d3a9 100644 --- a/shell/platform/android/android_surface_gl.h +++ b/shell/platform/android/android_surface_gl.h @@ -16,35 +16,43 @@ namespace shell { -class AndroidSurfaceGL : public GPUSurfaceGLDelegate, public AndroidSurface { +class AndroidSurfaceGL final : public GPUSurfaceGLDelegate, + public AndroidSurface { public: - explicit AndroidSurfaceGL(PlatformView::SurfaceConfig offscreen_config); + AndroidSurfaceGL(); ~AndroidSurfaceGL() override; - bool IsValid() const override; - bool IsOffscreenContextValid() const; + // |shell::AndroidSurface| + bool IsValid() const override; + + // |shell::AndroidSurface| std::unique_ptr CreateGPUSurface() override; + // |shell::AndroidSurface| void TeardownOnScreenContext() override; - SkISize OnScreenSurfaceSize() const override; - + // |shell::AndroidSurface| bool OnScreenSurfaceResize(const SkISize& size) const override; + // |shell::AndroidSurface| bool ResourceContextMakeCurrent() override; - bool SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config) override; + // |shell::AndroidSurface| + bool SetNativeWindow(fxl::RefPtr window) override; + // |shell::GPUSurfaceGLDelegate| bool GLContextMakeCurrent() override; + // |shell::GPUSurfaceGLDelegate| bool GLContextClearCurrent() override; + // |shell::GPUSurfaceGLDelegate| bool GLContextPresent() override; + // |shell::GPUSurfaceGLDelegate| intptr_t GLContextFBO() const override; private: diff --git a/shell/platform/android/android_surface_software.cc b/shell/platform/android/android_surface_software.cc index 68bf99b27ba56..4b1378802d9e4 100644 --- a/shell/platform/android/android_surface_software.cc +++ b/shell/platform/android/android_surface_software.cc @@ -3,15 +3,14 @@ // found in the LICENSE file. #include "flutter/shell/platform/android/android_surface_software.h" -#include "flutter/common/threads.h" -#include "flutter/fml/platform/android/jni_weak_ref.h" -#include "flutter/fml/platform/android/scoped_java_ref.h" -#include "flutter/shell/platform/android/platform_view_android_jni.h" #include #include +#include "flutter/fml/platform/android/jni_weak_ref.h" +#include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/trace_event.h" +#include "flutter/shell/platform/android/platform_view_android_jni.h" #include "lib/fxl/logging.h" namespace shell { @@ -132,17 +131,12 @@ bool AndroidSurfaceSoftware::PresentBackingStore( void AndroidSurfaceSoftware::TeardownOnScreenContext() {} -SkISize AndroidSurfaceSoftware::OnScreenSurfaceSize() const { - return SkISize(); -} - bool AndroidSurfaceSoftware::OnScreenSurfaceResize(const SkISize& size) const { return true; } bool AndroidSurfaceSoftware::SetNativeWindow( - fxl::RefPtr window, - PlatformView::SurfaceConfig config) { + fxl::RefPtr window) { native_window_ = std::move(window); if (!(native_window_ && native_window_->IsValid())) return false; diff --git a/shell/platform/android/android_surface_software.h b/shell/platform/android/android_surface_software.h index 76184b707cf74..0f82fc5dfe154 100644 --- a/shell/platform/android/android_surface_software.h +++ b/shell/platform/android/android_surface_software.h @@ -13,35 +13,39 @@ namespace shell { -class AndroidSurfaceSoftware : public AndroidSurface, - public GPUSurfaceSoftwareDelegate { +class AndroidSurfaceSoftware final : public AndroidSurface, + public GPUSurfaceSoftwareDelegate { public: AndroidSurfaceSoftware(); ~AndroidSurfaceSoftware() override; + // |shell::AndroidSurface| bool IsValid() const override; + // |shell::AndroidSurface| bool ResourceContextMakeCurrent() override; + // |shell::AndroidSurface| std::unique_ptr CreateGPUSurface() override; - sk_sp AcquireBackingStore(const SkISize& size) override; - - bool PresentBackingStore(sk_sp backing_store) override; - + // |shell::AndroidSurface| void TeardownOnScreenContext() override; - SkISize OnScreenSurfaceSize() const override; - + // |shell::AndroidSurface| bool OnScreenSurfaceResize(const SkISize& size) const override; - bool SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config) override; + // |shell::AndroidSurface| + bool SetNativeWindow(fxl::RefPtr window) override; + + // |shell::GPUSurfaceSoftwareDelegate| + sk_sp AcquireBackingStore(const SkISize& size) override; + + // |shell::GPUSurfaceSoftwareDelegate| + bool PresentBackingStore(sk_sp backing_store) override; private: sk_sp sk_surface_; - fxl::RefPtr native_window_; SkColorType target_color_type_; SkAlphaType target_alpha_type_; diff --git a/shell/platform/android/android_surface_vulkan.cc b/shell/platform/android/android_surface_vulkan.cc index ccacf538b8781..e8817690188c2 100644 --- a/shell/platform/android/android_surface_vulkan.cc +++ b/shell/platform/android/android_surface_vulkan.cc @@ -21,10 +21,12 @@ bool AndroidSurfaceVulkan::IsValid() const { return proc_table_->HasAcquiredMandatoryProcAddresses(); } +// |shell::AndroidSurface| void AndroidSurfaceVulkan::TeardownOnScreenContext() { - // + // Nothing to do. } +// |shell::AndroidSurface| std::unique_ptr AndroidSurfaceVulkan::CreateGPUSurface() { if (!IsValid()) { return nullptr; @@ -52,21 +54,20 @@ std::unique_ptr AndroidSurfaceVulkan::CreateGPUSurface() { return gpu_surface; } -SkISize AndroidSurfaceVulkan::OnScreenSurfaceSize() const { - return native_window_ ? native_window_->GetSize() : SkISize::Make(0, 0); -} - +// |shell::AndroidSurface| bool AndroidSurfaceVulkan::OnScreenSurfaceResize(const SkISize& size) const { return true; } +// |shell::AndroidSurface| bool AndroidSurfaceVulkan::ResourceContextMakeCurrent() { + FXL_DLOG(ERROR) << "The vulkan backend does not support resource contexts."; return false; } +// |shell::AndroidSurface| bool AndroidSurfaceVulkan::SetNativeWindow( - fxl::RefPtr window, - PlatformView::SurfaceConfig config) { + fxl::RefPtr window) { native_window_ = std::move(window); return native_window_ && native_window_->IsValid(); } diff --git a/shell/platform/android/android_surface_vulkan.h b/shell/platform/android/android_surface_vulkan.h index f1ecf610c8584..fd3f493d49790 100644 --- a/shell/platform/android/android_surface_vulkan.h +++ b/shell/platform/android/android_surface_vulkan.h @@ -20,20 +20,23 @@ class AndroidSurfaceVulkan : public AndroidSurface { ~AndroidSurfaceVulkan() override; + // |shell::AndroidSurface| bool IsValid() const override; - void TeardownOnScreenContext() override; - + // |shell::AndroidSurface| std::unique_ptr CreateGPUSurface() override; - SkISize OnScreenSurfaceSize() const override; + // |shell::AndroidSurface| + void TeardownOnScreenContext() override; + // |shell::AndroidSurface| bool OnScreenSurfaceResize(const SkISize& size) const override; + // |shell::AndroidSurface| bool ResourceContextMakeCurrent() override; - bool SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config) override; + // |shell::AndroidSurface| + bool SetNativeWindow(fxl::RefPtr window) override; private: fxl::RefPtr proc_table_; diff --git a/shell/platform/android/apk_asset_provider.cc b/shell/platform/android/apk_asset_provider.cc index fdd4910a12f4c..4cf6da16dc64f 100644 --- a/shell/platform/android/apk_asset_provider.cc +++ b/shell/platform/android/apk_asset_provider.cc @@ -7,32 +7,41 @@ namespace blink { +APKAssetProvider::APKAssetProvider(JNIEnv* env, + jobject jassetManager, + std::string directory) + : directory_(std::move(directory)) { + assetManager_ = AAssetManager_fromJava(env, jassetManager); +} + +APKAssetProvider::~APKAssetProvider() = default; + +bool APKAssetProvider::IsValid() const { + return true; +} + bool APKAssetProvider::GetAsBuffer(const std::string& asset_name, - std::vector* data) { + std::vector* data) const { std::stringstream ss; ss << directory_.c_str() << "/" << asset_name; - AAsset* asset = AAssetManager_open(assetManager_, ss.str().c_str(), AASSET_MODE_BUFFER); + AAsset* asset = + AAssetManager_open(assetManager_, ss.str().c_str(), AASSET_MODE_BUFFER); if (!asset) { - return false; + return false; } uint8_t* buffer = (uint8_t*)AAsset_getBuffer(asset); if (!buffer) { FXL_LOG(ERROR) << "Got null trying to acquire buffer for asset:" << asset; + AAsset_close(asset); return false; } data->resize(AAsset_getLength(asset)); std::copy(buffer, buffer + data->size(), data->begin()); + AAsset_close(asset); return true; } -APKAssetProvider::~APKAssetProvider() {} - -APKAssetProvider::APKAssetProvider(JNIEnv* env, jobject jassetManager, std::string directory) - : directory_(std::move(directory)) { - assetManager_ = AAssetManager_fromJava(env, jassetManager); -} - } // namespace blink diff --git a/shell/platform/android/apk_asset_provider.h b/shell/platform/android/apk_asset_provider.h index c40b1ed2a1866..70ddbe454bc61 100644 --- a/shell/platform/android/apk_asset_provider.h +++ b/shell/platform/android/apk_asset_provider.h @@ -5,28 +5,35 @@ #ifndef FLUTTER_ASSETS_APK_ASSET_PROVIDER_H_ #define FLUTTER_ASSETS_APK_ASSET_PROVIDER_H_ -#include #include +#include -#include "flutter/assets/asset_provider.h" +#include "flutter/assets/asset_resolver.h" #include "lib/fxl/memory/ref_counted.h" namespace blink { -class APKAssetProvider - : public AssetProvider { +class APKAssetProvider final : public AssetResolver { public: - explicit APKAssetProvider(JNIEnv* env, jobject assetManager, std::string directory); + explicit APKAssetProvider(JNIEnv* env, + jobject assetManager, + std::string directory); virtual ~APKAssetProvider(); + private: + AAssetManager* assetManager_; + const std::string directory_; + + // |blink::AssetResolver| + bool IsValid() const override; + + // |blink::AssetResolver| virtual bool GetAsBuffer(const std::string& asset_name, - std::vector* data); + std::vector* data) const override; - private: - AAssetManager* assetManager_; - const std::string directory_; + FXL_DISALLOW_COPY_AND_ASSIGN(APKAssetProvider); }; } // namespace blink -#endif // FLUTTER_ASSETS_APK_ASSET_PROVIDER_H \ No newline at end of file +#endif // FLUTTER_ASSETS_APK_ASSET_PROVIDER_H \ No newline at end of file diff --git a/shell/platform/android/flutter_main.cc b/shell/platform/android/flutter_main.cc index 6df346a128722..08d97add93b87 100644 --- a/shell/platform/android/flutter_main.cc +++ b/shell/platform/android/flutter_main.cc @@ -2,38 +2,85 @@ // 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/shell/platform/android/flutter_main.h" #include +#include "flutter/fml/message_loop.h" +#include "flutter/fml/paths.h" #include "flutter/fml/platform/android/jni_util.h" +#include "flutter/runtime/dart_vm.h" #include "flutter/runtime/start_up.h" #include "flutter/shell/common/shell.h" +#include "flutter/shell/common/switches.h" #include "lib/fxl/arraysize.h" #include "lib/fxl/command_line.h" +#include "lib/fxl/files/file.h" #include "lib/fxl/macros.h" #include "third_party/dart/runtime/include/dart_tools_api.h" namespace shell { -static void Init(JNIEnv* env, - jclass clazz, - jobject context, - jobjectArray jargs, - jstring bundlePath) { - // Prepare command line arguments and initialize the shell. +FlutterMain::FlutterMain(blink::Settings settings) + : settings_(std::move(settings)) {} + +FlutterMain::~FlutterMain() = default; + +static std::unique_ptr g_flutter_main; + +FlutterMain& FlutterMain::Get() { + FXL_CHECK(g_flutter_main) << "ensureInitializationComplete must have already " + "been called."; + return *g_flutter_main; +} + +const blink::Settings& FlutterMain::GetSettings() const { + return settings_; +} + +void FlutterMain::Init(JNIEnv* env, + jclass clazz, + jobject context, + jobjectArray jargs, + jstring bundlePath) { std::vector args; - args.push_back("flutter_tester"); + args.push_back("flutter"); for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) { args.push_back(std::move(arg)); } - auto command_line = fxl::CommandLineFromIterators(args.begin(), args.end()); - std::string icu_data_path = - command_line.GetOptionValueWithDefault("icu-data-file-path", ""); - Shell::InitStandalone(std::move(command_line), std::move(icu_data_path), - /* application_library_path= */ "", - fml::jni::JavaStringToString(env, bundlePath)); + + auto settings = SettingsFromCommandLine(command_line); + + settings.assets_path = fml::jni::JavaStringToString(env, bundlePath); + + if (!blink::DartVM::IsRunningPrecompiledCode()) { + // Check to see if the appropriate kernel files are present and configure + // settings accordingly. + auto platform_kernel_path = + fml::paths::JoinPaths({settings.assets_path, "platform.dill"}); + auto application_kernel_path = + fml::paths::JoinPaths({settings.assets_path, "kernel_blob.bin"}); + + if (files::IsFile(platform_kernel_path) && + files::IsFile(application_kernel_path)) { + settings.kernel_snapshot_path = platform_kernel_path; + settings.application_kernel_asset = application_kernel_path; + } + } + + settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { + fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); + }; + + settings.task_observer_remove = [](intptr_t key) { + fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); + }; + // Not thread safe. Will be removed when FlutterMain is refactored to no + // longer be a singleton. + g_flutter_main.reset(new FlutterMain(std::move(settings))); } static void RecordStartTimestamp(JNIEnv* env, @@ -44,7 +91,7 @@ static void RecordStartTimestamp(JNIEnv* env, blink::engine_main_enter_ts = Dart_TimelineGetMicros() - initTimeMicros; } -bool RegisterFlutterMain(JNIEnv* env) { +bool FlutterMain::Register(JNIEnv* env) { static const JNINativeMethod methods[] = { { .name = "nativeInit", diff --git a/shell/platform/android/flutter_main.h b/shell/platform/android/flutter_main.h index f4f65c499f966..6c8717e9cebdb 100644 --- a/shell/platform/android/flutter_main.h +++ b/shell/platform/android/flutter_main.h @@ -7,9 +7,34 @@ #include +#include "flutter/common/settings.h" +#include "lib/fxl/macros.h" + namespace shell { -bool RegisterFlutterMain(JNIEnv* env); +class FlutterMain { + public: + ~FlutterMain(); + + static bool Register(JNIEnv* env); + + static FlutterMain& Get(); + + const blink::Settings& GetSettings() const; + + private: + const blink::Settings settings_; + + FlutterMain(blink::Settings settings); + + static void Init(JNIEnv* env, + jclass clazz, + jobject context, + jobjectArray jargs, + jstring bundlePath); + + FXL_DISALLOW_COPY_AND_ASSIGN(FlutterMain); +}; } // namespace shell diff --git a/shell/platform/android/library_loader.cc b/shell/platform/android/library_loader.cc index c51d0114282f6..569825ce33e21 100644 --- a/shell/platform/android/library_loader.cc +++ b/shell/platform/android/library_loader.cc @@ -16,7 +16,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { bool result = false; // Register FlutterMain. - result = shell::RegisterFlutterMain(env); + result = shell::FlutterMain::Register(env); FXL_CHECK(result); // Register PlatformView diff --git a/shell/platform/android/platform_message_response_android.cc b/shell/platform/android/platform_message_response_android.cc new file mode 100644 index 0000000000000..214080ec5bde3 --- /dev/null +++ b/shell/platform/android/platform_message_response_android.cc @@ -0,0 +1,62 @@ +// 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/shell/platform/android/platform_message_response_android.h" + +#include "flutter/shell/platform/android/platform_view_android_jni.h" +#include "lib/fxl/functional/make_copyable.h" + +namespace shell { + +PlatformMessageResponseAndroid::PlatformMessageResponseAndroid( + int response_id, + fml::jni::JavaObjectWeakGlobalRef weak_java_object, + fxl::RefPtr platform_task_runner) + : response_id_(response_id), + weak_java_object_(weak_java_object), + platform_task_runner_(std::move(platform_task_runner)) {} + +// |blink::PlatformMessageResponse| +void PlatformMessageResponseAndroid::Complete(std::vector data) { + platform_task_runner_->PostTask( + fxl::MakeCopyable([response = response_id_, // + weak_java_object = weak_java_object_, // + data = std::move(data) // + ]() { + // We are on the platform thread. Attempt to get the strong reference to + // the Java object. + auto env = fml::jni::AttachCurrentThread(); + auto java_object = weak_java_object.get(env); + + if (java_object.is_null()) { + // The Java object was collected before this message response got to + // it. Drop the response on the floor. + return; + } + + if (data.size() == 0) { + // If the data is empty, there is no reason to create a Java byte + // array. Make the response now with a nullptr now. + FlutterViewHandlePlatformMessageResponse(env, java_object.obj(), + response, nullptr); + } + + // Convert the vector to a Java byte array. + fml::jni::ScopedJavaLocalRef data_array( + env, env->NewByteArray(data.size())); + env->SetByteArrayRegion(data_array.obj(), 0, data.size(), + reinterpret_cast(data.data())); + + // Make the response call into Java. + FlutterViewHandlePlatformMessageResponse(env, java_object.obj(), + response, data_array.obj()); + })); +} + +// |blink::PlatformMessageResponse| +void PlatformMessageResponseAndroid::CompleteEmpty() { + Complete(std::vector{}); +} + +} // namespace shell diff --git a/shell/platform/android/platform_message_response_android.h b/shell/platform/android/platform_message_response_android.h new file mode 100644 index 0000000000000..2ee7f3336ac6d --- /dev/null +++ b/shell/platform/android/platform_message_response_android.h @@ -0,0 +1,39 @@ +// 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_SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_RESPONSE_ANDROID_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_RESPONSE_ANDROID_H_ + +#include "flutter/fml/platform/android/jni_weak_ref.h" +#include "flutter/fml/task_runner.h" +#include "flutter/lib/ui/window/platform_message_response.h" +#include "lib/fxl/macros.h" + +namespace shell { + +class PlatformMessageResponseAndroid : public blink::PlatformMessageResponse { + public: + // |blink::PlatformMessageResponse| + void Complete(std::vector data) override; + + // |blink::PlatformMessageResponse| + void CompleteEmpty() override; + + private: + PlatformMessageResponseAndroid( + int response_id, + fml::jni::JavaObjectWeakGlobalRef weak_java_object, + fxl::RefPtr platform_task_runner); + + int response_id_; + fml::jni::JavaObjectWeakGlobalRef weak_java_object_; + fxl::RefPtr platform_task_runner_; + + FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseAndroid); + FXL_DISALLOW_COPY_AND_ASSIGN(PlatformMessageResponseAndroid); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_RESPONSE_ANDROID_H_ diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index 8f677045fb1f5..00d1e4b59e848 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -4,288 +4,55 @@ #include "flutter/shell/platform/android/platform_view_android.h" -#include -#include -#include -#include - +#include #include -#include "flutter/common/settings.h" -#include "flutter/common/threads.h" -#include "flutter/fml/platform/android/jni_util.h" -#include "flutter/fml/platform/android/scoped_java_ref.h" -#include "flutter/runtime/dart_service_isolate.h" -#include "flutter/shell/common/null_rasterizer.h" -#include "flutter/shell/gpu/gpu_rasterizer.h" +#include "flutter/shell/common/io_manager.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" #include "flutter/shell/platform/android/android_surface_gl.h" -#include "flutter/shell/platform/android/android_surface_software.h" -#include "flutter/shell/platform/android/apk_asset_provider.h" +#include "flutter/shell/platform/android/platform_message_response_android.h" #include "flutter/shell/platform/android/platform_view_android_jni.h" #include "flutter/shell/platform/android/vsync_waiter_android.h" -#include "lib/fxl/functional/make_copyable.h" - -#if SHELL_ENABLE_VULKAN -#include "flutter/shell/platform/android/android_surface_vulkan.h" -#endif // SHELL_ENABLE_VULKAN +#include "lib/fxl/synchronization/waitable_event.h" namespace shell { -class PlatformMessageResponseAndroid : public blink::PlatformMessageResponse { - FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseAndroid); - - public: - void Complete(std::vector data) override { - fxl::RefPtr self(this); - blink::Threads::Platform()->PostTask( - fxl::MakeCopyable([ self, data = std::move(data) ]() mutable { - std::shared_ptr view = self->view_.lock(); - if (!view) - return; - static_cast(view.get()) - ->HandlePlatformMessageResponse(self->response_id_, - std::move(data)); - })); - } - - void CompleteEmpty() override { - fxl::RefPtr self(this); - blink::Threads::Platform()->PostTask(fxl::MakeCopyable([self]() mutable { - std::shared_ptr view = self->view_.lock(); - if (!view) - return; - static_cast(view.get()) - ->HandlePlatformMessageEmptyResponse(self->response_id_); - })); - } - - private: - PlatformMessageResponseAndroid(int response_id, - std::weak_ptr view) - : response_id_(response_id), view_(view) {} - - int response_id_; - std::weak_ptr view_; -}; - -static std::unique_ptr InitializePlatformSurfaceGL() { - const PlatformView::SurfaceConfig offscreen_config = { - .red_bits = 8, - .green_bits = 8, - .blue_bits = 8, - .alpha_bits = 8, - .depth_bits = 0, - .stencil_bits = 0, - }; - auto surface = std::make_unique(offscreen_config); - return surface->IsOffscreenContextValid() ? std::move(surface) : nullptr; -} - -static std::unique_ptr InitializePlatformSurfaceVulkan() { -#if SHELL_ENABLE_VULKAN - auto surface = std::make_unique(); - return surface->IsValid() ? std::move(surface) : nullptr; -#else // SHELL_ENABLE_VULKAN - return nullptr; -#endif // SHELL_ENABLE_VULKAN +PlatformViewAndroid::PlatformViewAndroid( + PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + fml::jni::JavaObjectWeakGlobalRef java_object, + bool use_software_rendering) + : PlatformView(delegate, std::move(task_runners)), + java_object_(java_object), + android_surface_(AndroidSurface::Create(use_software_rendering)) { + FXL_CHECK(android_surface_) + << "Could not create an OpenGL, Vulkan or Software surface to setup " + "rendering."; } -static std::unique_ptr InitializePlatformSurfaceSoftware() { - auto surface = std::make_unique(); - return surface->IsValid() ? std::move(surface) : nullptr; -} - -static std::unique_ptr InitializePlatformSurface() { - if (blink::Settings::Get().enable_software_rendering) { - if (auto surface = InitializePlatformSurfaceSoftware()) { - FXL_DLOG(INFO) << "Software surface initialized."; - return surface; - } - } - - if (auto surface = InitializePlatformSurfaceVulkan()) { - FXL_DLOG(INFO) << "Vulkan surface initialized."; - return surface; - } - - FXL_DLOG(INFO) - << "Could not initialize Vulkan surface. Falling back to OpenGL."; - - if (auto surface = InitializePlatformSurfaceGL()) { - FXL_DLOG(INFO) << "GL surface initialized."; - return surface; - } - - if (auto surface = InitializePlatformSurfaceSoftware()) { - FXL_DLOG(INFO) << "Software surface initialized."; - return surface; - } - - FXL_CHECK(false) - << "Could not initialize either the Vulkan, OpenGL, or Software" - "surface backends. Flutter requires a GPU to render."; - return nullptr; -} - -PlatformViewAndroid::PlatformViewAndroid() - : PlatformView(std::make_unique()), - android_surface_(InitializePlatformSurface()) {} - PlatformViewAndroid::~PlatformViewAndroid() = default; -void PlatformViewAndroid::Attach() { - CreateEngine(); - - // Eagerly setup the IO thread context. We have already setup the surface. - SetupResourceContextOnIOThread(); - - UpdateThreadPriorities(); +void PlatformViewAndroid::NotifyCreated( + fxl::RefPtr native_window) { + InstallFirstFrameCallback(); + android_surface_->SetNativeWindow(native_window); + PlatformView::NotifyCreated(); } -void PlatformViewAndroid::Detach() { - ReleaseSurface(); -} - -void PlatformViewAndroid::SurfaceCreated(JNIEnv* env, - jobject jsurface, - jint backgroundColor) { - // Note: This frame ensures that any local references used by - // ANativeWindow_fromSurface are released immediately. This is needed as a - // workaround for https://code.google.com/p/android/issues/detail?id=68174 - fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env); - - // We have a drawing surface, so swap in a non-Null rasterizer. - SetRasterizer(std::make_unique(nullptr)); - - rasterizer_->AddNextFrameCallback([this]() { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); - if (!view.is_null()) { - FlutterViewOnFirstFrame(env, view.obj()); - } - }); - - auto native_window = fxl::MakeRefCounted( - ANativeWindow_fromSurface(env, jsurface)); - - if (!native_window->IsValid()) { - return; - } - - if (!android_surface_->SetNativeWindow(native_window)) { - return; - } - - std::unique_ptr gpu_surface = android_surface_->CreateGPUSurface(); - - if (gpu_surface == nullptr || !gpu_surface->IsValid()) { - return; - } - - NotifyCreated(std::move(gpu_surface), [ - this, backgroundColor, native_window_size = native_window->GetSize() - ] { rasterizer().Clear(backgroundColor, native_window_size); }); -} - -void PlatformViewAndroid::SurfaceChanged(jint width, jint height) { - blink::Threads::Gpu()->PostTask([this, width, height]() { - if (android_surface_) { - android_surface_->OnScreenSurfaceResize(SkISize::Make(width, height)); - } - }); -} - -void PlatformViewAndroid::UpdateThreadPriorities() { - blink::Threads::Gpu()->PostTask( - []() { ::setpriority(PRIO_PROCESS, gettid(), -2); }); - - blink::Threads::UI()->PostTask( - []() { ::setpriority(PRIO_PROCESS, gettid(), -1); }); -} - -void PlatformViewAndroid::SurfaceDestroyed() { - ReleaseSurface(); -} - -void PlatformViewAndroid::RunBundleAndSnapshot(JNIEnv* env, std::string bundle_path, - std::string snapshot_override, - std::string entrypoint, - bool reuse_runtime_controller, - jobject assetManager) { - // TODO(jsimmons): remove snapshot_override from the public FlutterView API - FXL_CHECK(snapshot_override.empty()) << "snapshot_override is obsolete"; - - // The flutter assets directory name is the last directory of the bundle_path - // and the path into the APK - size_t last_slash_idx = bundle_path.rfind("/", bundle_path.size()); - std::string flutter_assets_dir = bundle_path.substr( - last_slash_idx + 1, bundle_path.size() - last_slash_idx); - - fxl::RefPtr asset_provider = - fxl::MakeRefCounted(env, assetManager, - flutter_assets_dir); - blink::Threads::UI()->PostTask( - [engine = engine_->GetWeakPtr(), - asset_provider = std::move(asset_provider), - bundle_path = std::move(bundle_path), entrypoint = std::move(entrypoint), - reuse_runtime_controller = reuse_runtime_controller] { - if (engine) - engine->RunBundleWithAssets( - std::move(asset_provider), std::move(bundle_path), - std::move(entrypoint), reuse_runtime_controller); - }); -} - -void PlatformViewAndroid::RunBundleAndSource(std::string bundle_path, - std::string main, - std::string packages) { - blink::Threads::UI()->PostTask([ - engine = engine_->GetWeakPtr(), bundle_path = std::move(bundle_path), - main = std::move(main), packages = std::move(packages) - ] { - if (engine) - engine->RunBundleAndSource(std::move(bundle_path), std::move(main), - std::move(packages)); - }); +void PlatformViewAndroid::NotifyDestroyed() { + PlatformView::NotifyDestroyed(); + android_surface_->TeardownOnScreenContext(); } -void PlatformViewAndroid::SetAssetBundlePathOnUI(std::string bundle_path) { - blink::Threads::UI()->PostTask( - [ engine = engine_->GetWeakPtr(), bundle_path = std::move(bundle_path) ] { - if (engine) - engine->SetAssetBundlePath(std::move(bundle_path)); +void PlatformViewAndroid::NotifyChanged(const SkISize& size) { + fxl::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetGPUTaskRunner(), // + [&latch, surface = android_surface_.get(), size]() { + surface->OnScreenSurfaceResize(size); + latch.Signal(); }); -} - -void PlatformViewAndroid::SetViewportMetrics(jfloat device_pixel_ratio, - jint physical_width, - jint physical_height, - jint physical_padding_top, - jint physical_padding_right, - jint physical_padding_bottom, - jint physical_padding_left, - jint physical_view_inset_top, - jint physical_view_inset_right, - jint physical_view_inset_bottom, - jint physical_view_inset_left) { - blink::ViewportMetrics metrics; - metrics.device_pixel_ratio = device_pixel_ratio; - metrics.physical_width = physical_width; - metrics.physical_height = physical_height; - metrics.physical_padding_top = physical_padding_top; - metrics.physical_padding_right = physical_padding_right; - metrics.physical_padding_bottom = physical_padding_bottom; - metrics.physical_padding_left = physical_padding_left; - metrics.physical_view_inset_top = physical_view_inset_top; - metrics.physical_view_inset_right = physical_view_inset_right; - metrics.physical_view_inset_bottom = physical_view_inset_bottom; - metrics.physical_view_inset_left = physical_view_inset_left; - - blink::Threads::UI()->PostTask([ engine = engine_->GetWeakPtr(), metrics ] { - if (engine) - engine->SetViewportMetrics(metrics); - }); + latch.Wait(); } void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, @@ -301,7 +68,7 @@ void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, fxl::RefPtr response; if (response_id) { response = fxl::MakeRefCounted( - response_id, GetWeakPtr()); + response_id, java_object_, task_runners_.GetPlatformTaskRunner()); } PlatformView::DispatchPlatformMessage( @@ -315,7 +82,7 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env, fxl::RefPtr response; if (response_id) { response = fxl::MakeRefCounted( - response_id, GetWeakPtr()); + response_id, java_object_, task_runners_.GetPlatformTaskRunner()); } PlatformView::DispatchPlatformMessage( @@ -323,20 +90,6 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env, std::move(response))); } -void PlatformViewAndroid::DispatchPointerDataPacket(JNIEnv* env, - jobject buffer, - jint position) { - uint8_t* data = static_cast(env->GetDirectBufferAddress(buffer)); - - blink::Threads::UI()->PostTask(fxl::MakeCopyable([ - engine = engine_->GetWeakPtr(), - packet = std::make_unique(data, position) - ] { - if (engine.get()) - engine->DispatchPointerDataPacket(*packet); - })); -} - void PlatformViewAndroid::InvokePlatformMessageResponseCallback( JNIEnv* env, jint response_id, @@ -369,10 +122,11 @@ void PlatformViewAndroid::InvokePlatformMessageEmptyResponseCallback( message_response->CompleteEmpty(); } +// |shell::PlatformView| void PlatformViewAndroid::HandlePlatformMessage( fxl::RefPtr message) { JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); + fml::jni::ScopedJavaLocalRef view = java_object_.get(env); if (view.is_null()) return; @@ -402,35 +156,6 @@ void PlatformViewAndroid::HandlePlatformMessage( } } -void PlatformViewAndroid::HandlePlatformMessageResponse( - int response_id, - std::vector data) { - JNIEnv* env = fml::jni::AttachCurrentThread(); - - fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); - - if (view.is_null()) - return; - fml::jni::ScopedJavaLocalRef data_array( - env, env->NewByteArray(data.size())); - env->SetByteArrayRegion(data_array.obj(), 0, data.size(), - reinterpret_cast(data.data())); - - FlutterViewHandlePlatformMessageResponse(env, view.obj(), response_id, - data_array.obj()); -} - -void PlatformViewAndroid::HandlePlatformMessageEmptyResponse(int response_id) { - JNIEnv* env = fml::jni::AttachCurrentThread(); - - fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); - - if (view.is_null()) - return; - FlutterViewHandlePlatformMessageResponse(env, view.obj(), response_id, - nullptr); -} - void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env, jint id, jint action, @@ -451,35 +176,14 @@ void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env, id, static_cast(action), std::move(args_vector)); } -void PlatformViewAndroid::SetSemanticsEnabled(jboolean enabled) { - PlatformView::SetSemanticsEnabled(enabled); -} - -void PlatformViewAndroid::ReleaseSurface() { - NotifyDestroyed(); - android_surface_->TeardownOnScreenContext(); - SetRasterizer(std::make_unique()); -} - -VsyncWaiter* PlatformViewAndroid::GetVsyncWaiter() { - if (!vsync_waiter_) - vsync_waiter_ = std::make_unique(); - return vsync_waiter_.get(); -} - -bool PlatformViewAndroid::ResourceContextMakeCurrent() { - FXL_CHECK(android_surface_); - return android_surface_->ResourceContextMakeCurrent(); -} - -void PlatformViewAndroid::UpdateSemantics( - blink::SemanticsNodeUpdates update) { +// |shell::PlatformView| +void PlatformViewAndroid::UpdateSemantics(blink::SemanticsNodeUpdates update) { constexpr size_t kBytesPerNode = 36 * sizeof(int32_t); constexpr size_t kBytesPerChild = sizeof(int32_t); JNIEnv* env = fml::jni::AttachCurrentThread(); { - fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); + fml::jni::ScopedJavaLocalRef view = java_object_.get(env); if (view.is_null()) return; @@ -560,79 +264,6 @@ void PlatformViewAndroid::UpdateSemantics( } } -void PlatformViewAndroid::RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) { - JNIEnv* env = fml::jni::AttachCurrentThread(); - FXL_CHECK(env); - - { - fml::jni::ScopedJavaLocalRef local_flutter_view = - flutter_view_.get(env); - if (local_flutter_view.is_null()) { - // Collected. - return; - } - - // Grab the class of the flutter view. - jclass flutter_view_class = env->GetObjectClass(local_flutter_view.obj()); - FXL_CHECK(flutter_view_class); - - // Grab the runFromSource method id. - jmethodID run_from_source_method_id = env->GetMethodID( - flutter_view_class, "runFromSource", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - FXL_CHECK(run_from_source_method_id); - - // Invoke runFromSource on the Android UI thread. - jstring java_assets_directory = env->NewStringUTF(assets_directory.c_str()); - FXL_CHECK(java_assets_directory); - jstring java_main = env->NewStringUTF(main.c_str()); - FXL_CHECK(java_main); - jstring java_packages = env->NewStringUTF(packages.c_str()); - FXL_CHECK(java_packages); - env->CallVoidMethod(local_flutter_view.obj(), run_from_source_method_id, - java_assets_directory, java_main, java_packages); - } - - // Detaching from the VM deletes any stray local references. - fml::jni::DetachFromVM(); -} - -void PlatformViewAndroid::SetAssetBundlePath( - const std::string& assets_directory) { - JNIEnv* env = fml::jni::AttachCurrentThread(); - FXL_CHECK(env); - - { - fml::jni::ScopedJavaLocalRef local_flutter_view = - flutter_view_.get(env); - if (local_flutter_view.is_null()) { - // Collected. - return; - } - - // Grab the class of the flutter view. - jclass flutter_view_class = env->GetObjectClass(local_flutter_view.obj()); - FXL_CHECK(flutter_view_class); - - // Grab the setAssetBundlePath method id. - jmethodID method_id = env->GetMethodID( - flutter_view_class, "setAssetBundlePathOnUI", "(Ljava/lang/String;)V"); - FXL_CHECK(method_id); - - // Invoke setAssetBundlePath on the Android UI thread. - jstring java_assets_directory = env->NewStringUTF(assets_directory.c_str()); - FXL_CHECK(java_assets_directory); - - env->CallVoidMethod(local_flutter_view.obj(), method_id, - java_assets_directory); - } - - // Detaching from the VM deletes any stray local references. - fml::jni::DetachFromVM(); -} - void PlatformViewAndroid::RegisterExternalTexture( int64_t texture_id, const fml::jni::JavaObjectWeakGlobalRef& surface_texture) { @@ -640,116 +271,56 @@ void PlatformViewAndroid::RegisterExternalTexture( std::make_shared(texture_id, surface_texture)); } -void PlatformViewAndroid::MarkTextureFrameAvailable(int64_t texture_id) { - blink::Threads::Gpu()->PostTask([this, texture_id]() { - std::shared_ptr texture = - static_pointer_cast( - rasterizer_->GetTextureRegistry().GetTexture(texture_id)); - if (texture) { - texture->MarkNewFrameAvailable(); - } - }); - PlatformView::MarkTextureFrameAvailable(texture_id); +// |shell::PlatformView| +std::unique_ptr PlatformViewAndroid::CreateVSyncWaiter() { + return std::make_unique(task_runners_); } -fml::jni::ScopedJavaLocalRef PlatformViewAndroid::GetBitmap( - JNIEnv* env) { - // Render the last frame to an array of pixels on the GPU thread. - // The pixels will be returned as a global JNI reference to an int array. - fxl::AutoResetWaitableEvent latch; - jobject pixels_ref = nullptr; - SkISize frame_size; - blink::Threads::Gpu()->PostTask([this, &latch, &pixels_ref, &frame_size]() { - GetBitmapGpuTask(&pixels_ref, &frame_size); - latch.Signal(); - }); - - latch.Wait(); - - // Convert the pixel array to an Android bitmap. - if (pixels_ref == nullptr) - return fml::jni::ScopedJavaLocalRef(); - - fml::jni::ScopedJavaGlobalRef pixels(env, pixels_ref); - - jclass bitmap_class = env->FindClass("android/graphics/Bitmap"); - FXL_CHECK(bitmap_class); - - jmethodID create_bitmap = env->GetStaticMethodID( - bitmap_class, "createBitmap", - "([IIILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); - FXL_CHECK(create_bitmap); - - jclass bitmap_config_class = env->FindClass("android/graphics/Bitmap$Config"); - FXL_CHECK(bitmap_config_class); - - jmethodID bitmap_config_value_of = env->GetStaticMethodID( - bitmap_config_class, "valueOf", - "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;"); - FXL_CHECK(bitmap_config_value_of); - - jstring argb = env->NewStringUTF("ARGB_8888"); - FXL_CHECK(argb); - - jobject bitmap_config = env->CallStaticObjectMethod( - bitmap_config_class, bitmap_config_value_of, argb); - FXL_CHECK(bitmap_config); +// |shell::PlatformView| +std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { + return android_surface_->CreateGPUSurface(); +} - jobject bitmap = env->CallStaticObjectMethod( - bitmap_class, create_bitmap, pixels.obj(), frame_size.width(), - frame_size.height(), bitmap_config); +// |shell::PlatformView| +sk_sp PlatformViewAndroid::CreateResourceContext() const { + sk_sp resource_context; + if (android_surface_->ResourceContextMakeCurrent()) { + // TODO(chinmaygarde): Currently, this code depends on the fact that only + // the OpenGL surface will be able to make a resource context current. If + // this changes, this assumption breaks. Handle the same. + resource_context = IOManager::CreateCompatibleResourceLoadingContext( + GrBackend::kOpenGL_GrBackend); + } else { + FXL_DLOG(ERROR) << "Could not make the resource context current."; + } - return fml::jni::ScopedJavaLocalRef(env, bitmap); + return resource_context; +} + +void PlatformViewAndroid::InstallFirstFrameCallback() { + // On Platform Task Runner. + SetNextFrameCallback( + [platform_view = GetWeakPtr(), + platform_task_runner = task_runners_.GetPlatformTaskRunner()]() { + // On GPU Task Runner. + platform_task_runner->PostTask([platform_view]() { + // Back on Platform Task Runner. + if (platform_view) { + reinterpret_cast(platform_view.get()) + ->FireFirstFrameCallback(); + } + }); + }); } -void PlatformViewAndroid::GetBitmapGpuTask(jobject* pixels_out, - SkISize* size_out) { - flow::LayerTree* layer_tree = rasterizer_->GetLastLayerTree(); - if (layer_tree == nullptr) - return; - +void PlatformViewAndroid::FireFirstFrameCallback() { JNIEnv* env = fml::jni::AttachCurrentThread(); - FXL_CHECK(env); - - const SkISize& frame_size = layer_tree->frame_size(); - jsize pixels_size = frame_size.width() * frame_size.height(); - jintArray pixels_array = env->NewIntArray(pixels_size); - FXL_CHECK(pixels_array); - - jint* pixels = env->GetIntArrayElements(pixels_array, nullptr); - FXL_CHECK(pixels); - - SkImageInfo image_info = - SkImageInfo::Make(frame_size.width(), frame_size.height(), - kRGBA_8888_SkColorType, kPremul_SkAlphaType); - - sk_sp surface = SkSurface::MakeRasterDirect( - image_info, pixels, frame_size.width() * sizeof(jint)); - - flow::CompositorContext compositor_context(nullptr); - compositor_context.SetTextureRegistry(&texture_registry_); - SkCanvas* canvas = surface->getCanvas(); - flow::CompositorContext::ScopedFrame frame = - compositor_context.AcquireFrame(nullptr, canvas, false); - - canvas->clear(SK_ColorBLACK); - layer_tree->Raster(frame); - canvas->flush(); - - // Our configuration of Skia does not support rendering to the - // BitmapConfig.ARGB_8888 format expected by android.graphics.Bitmap. - // Convert from kRGBA_8888 to kBGRA_8888 (equivalent to ARGB_8888). - for (int i = 0; i < pixels_size; i++) { - uint8_t* bytes = reinterpret_cast(pixels + i); - std::swap(bytes[0], bytes[2]); + fml::jni::ScopedJavaLocalRef view = java_object_.get(env); + if (view.is_null()) { + // The Java object died. + return; } - - env->ReleaseIntArrayElements(pixels_array, pixels, 0); - - *pixels_out = env->NewGlobalRef(pixels_array); - *size_out = frame_size; - - fml::jni::DetachFromVM(); + FlutterViewOnFirstFrame(fml::jni::AttachCurrentThread(), view.obj()); } } // namespace shell diff --git a/shell/platform/android/platform_view_android.h b/shell/platform/android/platform_view_android.h index 4779ea16ab4a7..9976c443f4248 100644 --- a/shell/platform/android/platform_view_android.h +++ b/shell/platform/android/platform_view_android.h @@ -20,45 +20,23 @@ namespace shell { -class PlatformViewAndroid : public PlatformView { +class PlatformViewAndroid final : public PlatformView { public: static bool Register(JNIEnv* env); - PlatformViewAndroid(); + PlatformViewAndroid(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + fml::jni::JavaObjectWeakGlobalRef java_object, + bool use_software_rendering); ~PlatformViewAndroid() override; - virtual void Attach() override; + void NotifyCreated(fxl::RefPtr native_window); - void Detach(); + void NotifyChanged(const SkISize& size); - void SurfaceCreated(JNIEnv* env, jobject jsurface, jint backgroundColor); - - void SurfaceChanged(jint width, jint height); - - void SurfaceDestroyed(); - - void RunBundleAndSnapshot(JNIEnv* env, std::string bundle_path, - std::string snapshot_override, - std::string entrypoint, - bool reuse_isolate, - jobject assetManager); - - void RunBundleAndSource(std::string bundle_path, - std::string main, - std::string packages); - - void SetViewportMetrics(jfloat device_pixel_ratio, - jint physical_width, - jint physical_height, - jint physical_padding_top, - jint physical_padding_right, - jint physical_padding_bottom, - jint physical_padding_left, - jint physical_view_inset_top, - jint physical_view_inset_right, - jint physical_view_inset_bottom, - jint physical_view_inset_left); + // |shell::PlatformView| + void NotifyDestroyed() override; void DispatchPlatformMessage(JNIEnv* env, std::string name, @@ -70,8 +48,6 @@ class PlatformViewAndroid : public PlatformView { std::string name, jint response_id); - void DispatchPointerDataPacket(JNIEnv* env, jobject buffer, jint position); - void InvokePlatformMessageResponseCallback(JNIEnv* env, jint response_id, jobject java_response_data, @@ -86,55 +62,37 @@ class PlatformViewAndroid : public PlatformView { jobject args, jint args_position); - void SetSemanticsEnabled(jboolean enabled); - - fml::jni::ScopedJavaLocalRef GetBitmap(JNIEnv* env); - - VsyncWaiter* GetVsyncWaiter() override; - - bool ResourceContextMakeCurrent() override; - - void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - - void HandlePlatformMessage( - fxl::RefPtr message) override; - - void HandlePlatformMessageResponse(int response_id, - std::vector data); - - void HandlePlatformMessageEmptyResponse(int response_id); - - void RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) override; - - void SetAssetBundlePathOnUI(std::string bundle_path); - - void SetAssetBundlePath(const std::string& assets_directory) override; - void RegisterExternalTexture( int64_t texture_id, const fml::jni::JavaObjectWeakGlobalRef& surface_texture); - void MarkTextureFrameAvailable(int64_t texture_id) override; - - void set_flutter_view(const fml::jni::JavaObjectWeakGlobalRef& flutter_view) { - flutter_view_ = flutter_view; - } - private: - std::unique_ptr android_surface_; - fml::jni::JavaObjectWeakGlobalRef flutter_view_; + const fml::jni::JavaObjectWeakGlobalRef java_object_; + const std::unique_ptr android_surface_; // We use id 0 to mean that no response is expected. int next_response_id_ = 1; std::unordered_map> pending_responses_; - void UpdateThreadPriorities(); + // |shell::PlatformView| + void UpdateSemantics(blink::SemanticsNodeUpdates update) override; + + // |shell::PlatformView| + void HandlePlatformMessage( + fxl::RefPtr message) override; + + // |shell::PlatformView| + std::unique_ptr CreateVSyncWaiter() override; + + // |shell::PlatformView| + std::unique_ptr CreateRenderingSurface() override; + + // |shell::PlatformView| + sk_sp CreateResourceContext() const override; - void ReleaseSurface(); + void InstallFirstFrameCallback(); - void GetBitmapGpuTask(jobject* pixels_out, SkISize* size_out); + void FireFirstFrameCallback(); FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewAndroid); }; diff --git a/shell/platform/android/platform_view_android_jni.cc b/shell/platform/android/platform_view_android_jni.cc index c819f3bfb5e41..f75f54a896850 100644 --- a/shell/platform/android/platform_view_android_jni.cc +++ b/shell/platform/android/platform_view_android_jni.cc @@ -4,17 +4,26 @@ #include "flutter/shell/platform/android/platform_view_android_jni.h" +#include + +#include + +#include "flutter/assets/directory_asset_bundle.h" #include "flutter/common/settings.h" +#include "flutter/fml/file.h" #include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/jni_weak_ref.h" #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/runtime/dart_service_isolate.h" +#include "flutter/shell/common/run_configuration.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" +#include "flutter/shell/platform/android/android_shell_holder.h" +#include "flutter/shell/platform/android/apk_asset_provider.h" +#include "flutter/shell/platform/android/flutter_main.h" #include "lib/fxl/arraysize.h" -#include "lib/fxl/logging.h" -#define PLATFORM_VIEW \ - (*reinterpret_cast*>(platform_view)) +#define ANDROID_SHELL_HOLDER \ + (reinterpret_cast(shell_holder)) namespace shell { @@ -78,14 +87,12 @@ void FlutterViewOnFirstFrame(JNIEnv* env, jobject obj) { static jmethodID g_attach_to_gl_context_method = nullptr; void SurfaceTextureAttachToGLContext(JNIEnv* env, jobject obj, jint textureId) { - ASSERT_IS_GPU_THREAD; env->CallVoidMethod(obj, g_attach_to_gl_context_method, textureId); FXL_CHECK(CheckException(env)); } static jmethodID g_update_tex_image_method = nullptr; void SurfaceTextureUpdateTexImage(JNIEnv* env, jobject obj) { - ASSERT_IS_GPU_THREAD; env->CallVoidMethod(obj, g_update_tex_image_method); FXL_CHECK(CheckException(env)); } @@ -94,14 +101,12 @@ static jmethodID g_get_transform_matrix_method = nullptr; void SurfaceTextureGetTransformMatrix(JNIEnv* env, jobject obj, jfloatArray result) { - ASSERT_IS_GPU_THREAD; env->CallVoidMethod(obj, g_get_transform_matrix_method, result); FXL_CHECK(CheckException(env)); } static jmethodID g_detach_from_gl_context_method = nullptr; void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj) { - ASSERT_IS_GPU_THREAD; env->CallVoidMethod(obj, g_detach_from_gl_context_method); FXL_CHECK(CheckException(env)); } @@ -109,22 +114,22 @@ void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj) { // Called By Java static jlong Attach(JNIEnv* env, jclass clazz, jobject flutterView) { - auto view = new PlatformViewAndroid(); - auto storage = new std::shared_ptr(view); - // Create a weak reference to the flutterView Java object so that we can make - // calls into it later. - view->Attach(); - view->set_flutter_view(fml::jni::JavaObjectWeakGlobalRef(env, flutterView)); - return reinterpret_cast(storage); + fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterView); + auto shell_holder = std::make_unique( + FlutterMain::Get().GetSettings(), java_object); + if (shell_holder->IsValid()) { + return reinterpret_cast(shell_holder.release()); + } else { + return 0; + } } -static void Detach(JNIEnv* env, jobject jcaller, jlong platform_view) { - PLATFORM_VIEW->Detach(); +static void Detach(JNIEnv* env, jobject jcaller, jlong shell_holder) { + // Nothing to do. } -static void Destroy(JNIEnv* env, jobject jcaller, jlong platform_view) { - PLATFORM_VIEW->Detach(); - delete &PLATFORM_VIEW; +static void Destroy(JNIEnv* env, jobject jcaller, jlong shell_holder) { + delete ANDROID_SHELL_HOLDER; } static jstring GetObservatoryUri(JNIEnv* env, jclass clazz) { @@ -134,67 +139,180 @@ static jstring GetObservatoryUri(JNIEnv* env, jclass clazz) { static void SurfaceCreated(JNIEnv* env, jobject jcaller, - jlong platform_view, - jobject surface, + jlong shell_holder, + jobject jsurface, jint backgroundColor) { - return PLATFORM_VIEW->SurfaceCreated(env, surface, backgroundColor); + // Note: This frame ensures that any local references used by + // ANativeWindow_fromSurface are released immediately. This is needed as a + // workaround for https://code.google.com/p/android/issues/detail?id=68174 + fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env); + auto window = fxl::MakeRefCounted( + ANativeWindow_fromSurface(env, jsurface)); + ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window)); } static void SurfaceChanged(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jint width, jint height) { - return PLATFORM_VIEW->SurfaceChanged(width, height); -} - -static void SurfaceDestroyed(JNIEnv* env, - jobject jcaller, - jlong platform_view) { - return PLATFORM_VIEW->SurfaceDestroyed(); -} - -static void RunBundleAndSnapshot(JNIEnv* env, - jobject jcaller, - jlong platform_view, - jstring bundlePath, - jstring snapshotOverride, - jstring entrypoint, - jboolean reuse_runtime_controller, - jobject assetManager) { - return PLATFORM_VIEW->RunBundleAndSnapshot( - env, - fml::jni::JavaStringToString(env, bundlePath), // - fml::jni::JavaStringToString(env, snapshotOverride), // - fml::jni::JavaStringToString(env, entrypoint), // - reuse_runtime_controller, // - assetManager - ); + ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyChanged( + SkISize::Make(width, height)); } -void RunBundleAndSource(JNIEnv* env, - jobject jcaller, - jlong platform_view, - jstring bundlePath, - jstring main, - jstring packages) { - return PLATFORM_VIEW->RunBundleAndSource( - fml::jni::JavaStringToString(env, bundlePath), - fml::jni::JavaStringToString(env, main), - fml::jni::JavaStringToString(env, packages)); +static void SurfaceDestroyed(JNIEnv* env, jobject jcaller, jlong shell_holder) { + ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyDestroyed(); +} + +std::unique_ptr CreateIsolateConfiguration( + const blink::AssetManager& asset_manager) { + if (blink::DartVM::IsRunningPrecompiledCode()) { + return IsolateConfiguration::CreateForPrecompiledCode(); + } + + const auto configuration_from_blob = + [&asset_manager](const std::string& snapshot_name) + -> std::unique_ptr { + std::vector blob; + if (asset_manager.GetAsBuffer(snapshot_name, &blob)) { + return IsolateConfiguration::CreateForSnapshot( + std::make_unique(std::move(blob))); + } + return nullptr; + }; + + if (auto kernel = configuration_from_blob("kernel_blob.bin")) { + return kernel; + } + + if (auto script = configuration_from_blob("snapshot_blob.bin")) { + return script; + } + + return nullptr; +} + +static void RunBundleAndSnapshot( + JNIEnv* env, + jobject jcaller, + jlong shell_holder, + jstring jbundlepath, + jstring /* snapshot override (unused) */, + jstring jEntrypoint, + jboolean /* reuse runtime controller (unused) */, + jobject jAssetManager) { + auto asset_manager = fxl::MakeRefCounted(); + + const auto bundlepath = fml::jni::JavaStringToString(env, jbundlepath); + + if (bundlepath.size() > 0) { + // If we got a bundle path, attempt to use that as a directory asset + // bundle. + asset_manager->PushBack(std::make_unique( + fml::OpenFile(bundlepath.c_str(), fml::OpenPermission::kRead, true))); + + // Use the last path component of the bundle path to determine the + // directory in the APK assets. + const auto last_slash_index = bundlepath.rfind("/", bundlepath.size()); + if (last_slash_index != std::string::npos) { + auto apk_asset_dir = bundlepath.substr( + last_slash_index + 1, bundlepath.size() - last_slash_index); + + asset_manager->PushBack(std::make_unique( + env, // jni environment + jAssetManager, // asset manager + std::move(apk_asset_dir)) // apk asset dir + ); + } + } + + auto isolate_configuration = CreateIsolateConfiguration(*asset_manager); + + if (!isolate_configuration) { + FXL_DLOG(ERROR) + << "Isolate configuration could not be determined for engine launch."; + return; + } + + RunConfiguration config(std::move(isolate_configuration), + std::move(asset_manager)); + + { + auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint); + if (entrypoint.size() > 0) { + config.SetEntrypoint(std::move(entrypoint)); + } + } + + ANDROID_SHELL_HOLDER->Launch(std::move(config)); +} + +static void RunBundleAndSource(JNIEnv* env, + jobject jcaller, + jlong shell_holder, + jstring jBundlePath, + jstring main, + jstring packages) { + auto asset_manager = fxl::MakeRefCounted(); + + const auto bundlepath = fml::jni::JavaStringToString(env, jBundlePath); + + if (bundlepath.size() > 0) { + auto directory = + fml::OpenFile(bundlepath.c_str(), fml::OpenPermission::kRead, true); + asset_manager->PushBack( + std::make_unique(std::move(directory))); + } + + auto main_file_path = fml::jni::JavaStringToString(env, main); + auto packages_file_path = fml::jni::JavaStringToString(env, packages); + + auto config = + IsolateConfiguration::CreateForSource(main_file_path, packages_file_path); + + if (!config) { + return; + } + + RunConfiguration run_configuration(std::move(config), + std::move(asset_manager)); + + ANDROID_SHELL_HOLDER->Launch(std::move(run_configuration)); } void SetAssetBundlePathOnUI(JNIEnv* env, jobject jcaller, - jlong platform_view, - jstring bundlePath) { - return PLATFORM_VIEW->SetAssetBundlePathOnUI( - fml::jni::JavaStringToString(env, bundlePath)); + jlong shell_holder, + jstring jBundlePath) { + const auto bundlepath = fml::jni::JavaStringToString(env, jBundlePath); + + if (bundlepath.size() == 0) { + return; + } + + auto directory = + fml::OpenFile(bundlepath.c_str(), fml::OpenPermission::kRead, true); + + if (!directory.is_valid()) { + return; + } + + std::unique_ptr directory_asset_bundle = + std::make_unique(std::move(directory)); + + if (!directory_asset_bundle->IsValid()) { + return; + } + + auto asset_manager = fxl::MakeRefCounted(); + asset_manager->PushBack(std::move(directory_asset_bundle)); + + ANDROID_SHELL_HOLDER->UpdateAssetManager(std::move(asset_manager)); } static void SetViewportMetrics(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jfloat devicePixelRatio, jint physicalWidth, jint physicalHeight, @@ -206,115 +324,194 @@ static void SetViewportMetrics(JNIEnv* env, jint physicalViewInsetRight, jint physicalViewInsetBottom, jint physicalViewInsetLeft) { - return PLATFORM_VIEW->SetViewportMetrics(devicePixelRatio, // - physicalWidth, // - physicalHeight, // - physicalPaddingTop, // - physicalPaddingRight, // - physicalPaddingBottom, // - physicalPaddingLeft, // - physicalViewInsetTop, // - physicalViewInsetRight, // - physicalViewInsetBottom, // - physicalViewInsetLeft); + const blink::ViewportMetrics metrics = { + .device_pixel_ratio = devicePixelRatio, + .physical_width = physicalWidth, + .physical_height = physicalHeight, + .physical_padding_top = physicalPaddingTop, + .physical_padding_right = physicalPaddingRight, + .physical_padding_bottom = physicalPaddingBottom, + .physical_padding_left = physicalPaddingLeft, + .physical_view_inset_top = physicalViewInsetTop, + .physical_view_inset_right = physicalViewInsetRight, + .physical_view_inset_bottom = physicalViewInsetBottom, + .physical_view_inset_left = physicalViewInsetLeft, + }; + + ANDROID_SHELL_HOLDER->SetViewportMetrics(metrics); } -static jobject GetBitmap(JNIEnv* env, jobject jcaller, jlong platform_view) { - return PLATFORM_VIEW->GetBitmap(env).Release(); +static jobject GetBitmap(JNIEnv* env, jobject jcaller, jlong shell_holder) { + auto screenshot = ANDROID_SHELL_HOLDER->Screenshot( + Rasterizer::ScreenshotType::UncompressedImage, false); + if (screenshot.data == nullptr) { + return nullptr; + } + + const SkISize& frame_size = screenshot.frame_size; + jsize pixels_size = frame_size.width() * frame_size.height(); + jintArray pixels_array = env->NewIntArray(pixels_size); + FXL_CHECK(pixels_array); + + jint* pixels = env->GetIntArrayElements(pixels_array, nullptr); + FXL_CHECK(pixels); + + auto pixels_src = static_cast(screenshot.data->data()); + + // Our configuration of Skia does not support rendering to the + // BitmapConfig.ARGB_8888 format expected by android.graphics.Bitmap. + // Convert from kRGBA_8888 to kBGRA_8888 (equivalent to ARGB_8888). + for (int i = 0; i < pixels_size; i++) { + int32_t src_pixel = pixels_src[i]; + uint8_t* src_bytes = reinterpret_cast(&src_pixel); + std::swap(src_bytes[0], src_bytes[2]); + pixels[i] = src_pixel; + } + + env->ReleaseIntArrayElements(pixels_array, pixels, 0); + + jclass bitmap_class = env->FindClass("android/graphics/Bitmap"); + FXL_CHECK(bitmap_class); + + jmethodID create_bitmap = env->GetStaticMethodID( + bitmap_class, "createBitmap", + "([IIILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); + FXL_CHECK(create_bitmap); + + jclass bitmap_config_class = env->FindClass("android/graphics/Bitmap$Config"); + FXL_CHECK(bitmap_config_class); + + jmethodID bitmap_config_value_of = env->GetStaticMethodID( + bitmap_config_class, "valueOf", + "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;"); + FXL_CHECK(bitmap_config_value_of); + + jstring argb = env->NewStringUTF("ARGB_8888"); + FXL_CHECK(argb); + + jobject bitmap_config = env->CallStaticObjectMethod( + bitmap_config_class, bitmap_config_value_of, argb); + FXL_CHECK(bitmap_config); + + return env->CallStaticObjectMethod(bitmap_class, create_bitmap, pixels_array, + frame_size.width(), frame_size.height(), + bitmap_config); } static void DispatchPlatformMessage(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jstring channel, jobject message, jint position, jint responseId) { - return PLATFORM_VIEW->DispatchPlatformMessage( - env, fml::jni::JavaStringToString(env, channel), message, position, - responseId); + ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchPlatformMessage( + env, // + fml::jni::JavaStringToString(env, channel), // + message, // + position, // + responseId // + ); } static void DispatchEmptyPlatformMessage(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jstring channel, jint responseId) { - return PLATFORM_VIEW->DispatchEmptyPlatformMessage( - env, fml::jni::JavaStringToString(env, channel), responseId); + ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchEmptyPlatformMessage( + env, // + fml::jni::JavaStringToString(env, channel), // + responseId // + ); } static void DispatchPointerDataPacket(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jobject buffer, jint position) { - return PLATFORM_VIEW->DispatchPointerDataPacket(env, buffer, position); + uint8_t* data = static_cast(env->GetDirectBufferAddress(buffer)); + auto packet = std::make_unique(data, position); + ANDROID_SHELL_HOLDER->DispatchPointerDataPacket(std::move(packet)); } static void DispatchSemanticsAction(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jint id, jint action, jobject args, jint args_position) { - return PLATFORM_VIEW->DispatchSemanticsAction(env, id, action, args, - args_position); + ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchSemanticsAction( + env, // + id, // + action, // + args, // + args_position // + ); } static void SetSemanticsEnabled(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jboolean enabled) { - return PLATFORM_VIEW->SetSemanticsEnabled(enabled); + ANDROID_SHELL_HOLDER->GetPlatformView()->SetSemanticsEnabled(enabled); } static jboolean GetIsSoftwareRendering(JNIEnv* env, jobject jcaller) { - return blink::Settings::Get().enable_software_rendering; + return FlutterMain::Get().GetSettings().enable_software_rendering; } static void RegisterTexture(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jlong texture_id, jobject surface_texture) { - PLATFORM_VIEW->RegisterExternalTexture( - static_cast(texture_id), - fml::jni::JavaObjectWeakGlobalRef(env, surface_texture)); + ANDROID_SHELL_HOLDER->GetPlatformView()->RegisterExternalTexture( + static_cast(texture_id), // + fml::jni::JavaObjectWeakGlobalRef(env, surface_texture) // + ); } static void MarkTextureFrameAvailable(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jlong texture_id) { - return PLATFORM_VIEW->MarkTextureFrameAvailable( + ANDROID_SHELL_HOLDER->GetPlatformView()->MarkTextureFrameAvailable( static_cast(texture_id)); } static void UnregisterTexture(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jlong texture_id) { - PLATFORM_VIEW->UnregisterTexture(static_cast(texture_id)); + ANDROID_SHELL_HOLDER->GetPlatformView()->UnregisterTexture( + static_cast(texture_id)); } static void InvokePlatformMessageResponseCallback(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jint responseId, jobject message, jint position) { - return PLATFORM_VIEW->InvokePlatformMessageResponseCallback( - env, responseId, message, position); + ANDROID_SHELL_HOLDER->GetPlatformView() + ->InvokePlatformMessageResponseCallback(env, // + responseId, // + message, // + position // + ); } static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jint responseId) { - return PLATFORM_VIEW->InvokePlatformMessageEmptyResponseCallback(env, - responseId); + ANDROID_SHELL_HOLDER->GetPlatformView() + ->InvokePlatformMessageEmptyResponseCallback(env, // + responseId // + ); } bool PlatformViewAndroid::Register(JNIEnv* env) { @@ -353,8 +550,8 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { }, { .name = "nativeRunBundleAndSnapshot", - .signature = - "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLandroid/content/res/AssetManager;)V", + .signature = "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/" + "String;ZLandroid/content/res/AssetManager;)V", .fnPtr = reinterpret_cast(&shell::RunBundleAndSnapshot), }, { @@ -373,11 +570,6 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { .signature = "(J)V", .fnPtr = reinterpret_cast(&shell::Detach), }, - { - .name = "nativeDestroy", - .signature = "(J)V", - .fnPtr = reinterpret_cast(&shell::Destroy), - }, { .name = "nativeGetObservatoryUri", .signature = "()Ljava/lang/String;", diff --git a/shell/platform/android/vsync_waiter_android.cc b/shell/platform/android/vsync_waiter_android.cc index 29e1958dcc011..052de023b9a12 100644 --- a/shell/platform/android/vsync_waiter_android.cc +++ b/shell/platform/android/vsync_waiter_android.cc @@ -7,7 +7,7 @@ #include #include -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/trace_event.h" @@ -16,68 +16,49 @@ namespace shell { +static jlong CreatePendingCallback(VsyncWaiter::Callback callback); + +static void ConsumePendingCallback(jlong java_baton, + fxl::TimePoint frame_start_time, + fxl::TimePoint frame_target_time); + static fml::jni::ScopedJavaGlobalRef* g_vsync_waiter_class = nullptr; static jmethodID g_async_wait_for_vsync_method_ = nullptr; -VsyncWaiterAndroid::VsyncWaiterAndroid() : weak_factory_(this) {} +VsyncWaiterAndroid::VsyncWaiterAndroid(blink::TaskRunners task_runners) + : VsyncWaiter(std::move(task_runners)) {} VsyncWaiterAndroid::~VsyncWaiterAndroid() = default; -void VsyncWaiterAndroid::AsyncWaitForVsync(Callback callback) { - FXL_DCHECK(!callback_); - callback_ = std::move(callback); - fml::WeakPtr* weak = - new fml::WeakPtr(); - *weak = weak_factory_.GetWeakPtr(); +// |shell::VsyncWaiter| +void VsyncWaiterAndroid::AwaitVSync() { + auto java_baton = + CreatePendingCallback(std::bind(&VsyncWaiterAndroid::FireCallback, // + this, // + std::placeholders::_1, // + std::placeholders::_2 // + )); - blink::Threads::Platform()->PostTask([weak] { + task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() { JNIEnv* env = fml::jni::AttachCurrentThread(); - env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), - g_async_wait_for_vsync_method_, - reinterpret_cast(weak)); + env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), // + g_async_wait_for_vsync_method_, // + java_baton // + ); }); } -void VsyncWaiterAndroid::OnVsync(int64_t frameTimeNanos, - int64_t frameTargetTimeNanos) { - Callback callback = std::move(callback_); - callback_ = Callback(); - blink::Threads::UI()->PostTask( - [callback, frameTimeNanos, frameTargetTimeNanos] { - callback(fxl::TimePoint::FromEpochDelta( - fxl::TimeDelta::FromNanoseconds(frameTimeNanos)), - fxl::TimePoint::FromEpochDelta( - fxl::TimeDelta::FromNanoseconds(frameTargetTimeNanos))); - }); -} - static void OnNativeVsync(JNIEnv* env, jclass jcaller, jlong frameTimeNanos, jlong frameTargetTimeNanos, - jlong cookie) { - // Note: The tag name must be "VSYNC" (it is special) so that the "Highlight - // Vsync" checkbox in the timeline can be enabled. - // See: https://github.com/catapult-project/catapult/blob/2091404475cbba9b786 - // 442979b6ec631305275a6/tracing/tracing/extras/vsync/vsync_auditor.html#L26 -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE - TRACE_EVENT1("flutter", "VSYNC", "mode", "basic"); -#else - { - constexpr size_t num_chars = sizeof(jlong) * CHAR_BIT * 3.4 + 2; - char deadline[num_chars]; - sprintf(deadline, "%lld", frameTargetTimeNanos / 1000); // microseconds - TRACE_EVENT2("flutter", "VSYNC", "mode", "basic", "deadline", deadline); - } -#endif - fml::WeakPtr* weak = - reinterpret_cast*>(cookie); - VsyncWaiterAndroid* waiter = weak->get(); - delete weak; - if (waiter) { - waiter->OnVsync(static_cast(frameTimeNanos), - static_cast(frameTargetTimeNanos)); - } + jlong java_baton) { + auto frame_time = fxl::TimePoint::FromEpochDelta( + fxl::TimeDelta::FromNanoseconds(frameTimeNanos)); + auto target_time = fxl::TimePoint::FromEpochDelta( + fxl::TimeDelta::FromNanoseconds(frameTargetTimeNanos)); + + ConsumePendingCallback(java_baton, frame_time, target_time); } bool VsyncWaiterAndroid::Register(JNIEnv* env) { @@ -105,4 +86,27 @@ bool VsyncWaiterAndroid::Register(JNIEnv* env) { return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0; } +struct PendingCallbackData { + VsyncWaiter::Callback callback; + + PendingCallbackData(VsyncWaiter::Callback p_callback) + : callback(std::move(p_callback)) { + FXL_DCHECK(callback); + } +}; + +static jlong CreatePendingCallback(VsyncWaiter::Callback callback) { + // This delete for this new is balanced in the consume call. + auto data = new PendingCallbackData(std::move(callback)); + return reinterpret_cast(data); +} + +static void ConsumePendingCallback(jlong java_baton, + fxl::TimePoint frame_start_time, + fxl::TimePoint frame_target_time) { + auto data = reinterpret_cast(java_baton); + data->callback(frame_start_time, frame_target_time); + delete data; +} + } // namespace shell diff --git a/shell/platform/android/vsync_waiter_android.h b/shell/platform/android/vsync_waiter_android.h index c73af4bfca6f0..fd72a0a21f563 100644 --- a/shell/platform/android/vsync_waiter_android.h +++ b/shell/platform/android/vsync_waiter_android.h @@ -12,22 +12,17 @@ namespace shell { -class VsyncWaiterAndroid : public VsyncWaiter { +class VsyncWaiterAndroid final : public VsyncWaiter { public: - VsyncWaiterAndroid(); - - ~VsyncWaiterAndroid() override; - static bool Register(JNIEnv* env); - void AsyncWaitForVsync(Callback callback) override; + VsyncWaiterAndroid(blink::TaskRunners task_runners); - void OnVsync(int64_t frameTimeNanos, int64_t frameTargetTimeNanos); + ~VsyncWaiterAndroid() override; private: - Callback callback_; - fml::WeakPtr self_; - fml::WeakPtrFactory weak_factory_; + // |shell::VsyncWaiter| + void AwaitVSync() override; FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterAndroid); }; diff --git a/shell/platform/darwin/BUILD.gn b/shell/platform/darwin/BUILD.gn index c971c443bcc30..c6f7acd6be76a 100644 --- a/shell/platform/darwin/BUILD.gn +++ b/shell/platform/darwin/BUILD.gn @@ -6,11 +6,8 @@ assert(is_mac || is_ios) group("darwin") { if (is_mac) { - deps = [ - "desktop:shell_standalone", - ] if (!is_fuchsia_host) { - deps += [ + deps = [ "desktop:shell_application_bundle", ] } @@ -45,15 +42,12 @@ source_set("flutter_channels") { "$flutter_root/runtime", "$flutter_root/shell/common", "$flutter_root/shell/gpu", - "$flutter_root/shell/testing", "$flutter_root/sky/engine/wtf", "//garnet/public/lib/fxl", "//third_party/skia", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] } executable("flutter_channels_unittests") { @@ -68,7 +62,7 @@ executable("flutter_channels_unittests") { deps = [ ":flutter_channels", - "//third_party/dart/runtime:libdart_jit", "$flutter_root/testing", + "//third_party/dart/runtime:libdart_jit", ] } diff --git a/shell/platform/darwin/common/BUILD.gn b/shell/platform/darwin/common/BUILD.gn index e6fa86366b080..a1023737973a7 100644 --- a/shell/platform/darwin/common/BUILD.gn +++ b/shell/platform/darwin/common/BUILD.gn @@ -9,28 +9,23 @@ source_set("common") { sources = [ "buffer_conversions.h", "buffer_conversions.mm", - "platform_mac.h", - "platform_mac.mm", - "process_info_mac.cc", - "process_info_mac.h", + "command_line.h", + "command_line.mm", ] set_sources_assignment_filter(sources_assignment_filter) deps = [ - "//third_party/dart/runtime:dart_api", "$flutter_root/common", "$flutter_root/flow", "$flutter_root/fml", "$flutter_root/runtime", "$flutter_root/shell/common", "$flutter_root/shell/gpu", - "$flutter_root/shell/testing", "$flutter_root/sky/engine/wtf", "//garnet/public/lib/fxl", + "//third_party/dart/runtime:dart_api", "//third_party/skia", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] } diff --git a/shell/platform/darwin/common/command_line.h b/shell/platform/darwin/common/command_line.h new file mode 100644 index 0000000000000..dfc995b90f378 --- /dev/null +++ b/shell/platform/darwin/common/command_line.h @@ -0,0 +1,17 @@ +// 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_SHELL_PLATFORM_DARWIN_COMMON_COMMAND_LINE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_COMMAND_LINE_H_ + +#include "lib/fxl/command_line.h" +#include "lib/fxl/macros.h" + +namespace shell { + +fxl::CommandLine CommandLineFromNSProcessInfo(); + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_COMMAND_LINE_H_ diff --git a/shell/platform/darwin/common/command_line.mm b/shell/platform/darwin/common/command_line.mm new file mode 100644 index 0000000000000..bf8d4cc9d40f4 --- /dev/null +++ b/shell/platform/darwin/common/command_line.mm @@ -0,0 +1,21 @@ +// 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/shell/platform/darwin/common/command_line.h" + +#import + +namespace shell { + +fxl::CommandLine CommandLineFromNSProcessInfo() { + std::vector args_vector; + + for (NSString* arg in [NSProcessInfo processInfo].arguments) { + args_vector.emplace_back(arg.UTF8String); + } + + return fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); +} + +} // namespace shell diff --git a/shell/platform/darwin/common/platform_mac.h b/shell/platform/darwin/common/platform_mac.h deleted file mode 100644 index 1989b25f11c43..0000000000000 --- a/shell/platform/darwin/common/platform_mac.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 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 SHELL_PLATFORM_MAC_PLATFORM_MAC_H_ -#define SHELL_PLATFORM_MAC_PLATFORM_MAC_H_ - -#include "flutter/shell/common/engine.h" - -namespace shell { - -void PlatformMacMain(std::string icu_data_path, - std::string application_library_path, - std::string bundle_path); - -bool AttemptLaunchFromCommandLineSwitches(Engine* engine); - -} // namespace shell - -#endif // SHELL_PLATFORM_MAC_PLATFORM_MAC_H_ diff --git a/shell/platform/darwin/common/platform_mac.mm b/shell/platform/darwin/common/platform_mac.mm deleted file mode 100644 index 5af35a430beef..0000000000000 --- a/shell/platform/darwin/common/platform_mac.mm +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2015 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. - -#include "flutter/shell/platform/darwin/common/platform_mac.h" - -#include - -#include "flutter/common/threads.h" -#include "flutter/fml/trace_event.h" -#include "flutter/runtime/start_up.h" -#include "flutter/shell/common/shell.h" -#include "flutter/shell/common/switches.h" -#include "flutter/shell/common/tracing_controller.h" -#include "flutter/sky/engine/wtf/MakeUnique.h" -#include "lib/fxl/command_line.h" -#include "lib/fxl/strings/string_view.h" -#include "third_party/dart/runtime/include/dart_tools_api.h" - -namespace shell { - -static fxl::CommandLine InitializedCommandLine() { - std::vector args_vector; - - for (NSString* arg in [NSProcessInfo processInfo].arguments) { - args_vector.emplace_back(arg.UTF8String); - } - - return fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); -} - -class EmbedderState { - public: - EmbedderState(std::string icu_data_path, - std::string application_library_path, - std::string bundle_path) { - blink::engine_main_enter_ts = Dart_TimelineGetMicros(); - FXL_DCHECK([NSThread isMainThread]) - << "Embedder initialization must occur on the main platform thread"; - - auto command_line = InitializedCommandLine(); - - // This is about as early as tracing of any kind can start. Add an instant - // marker that can be used as a reference for startup. - TRACE_EVENT_INSTANT0("flutter", "main"); - - shell::Shell::InitStandalone(std::move(command_line), icu_data_path, application_library_path, - bundle_path); - } - - ~EmbedderState() {} - - private: - FXL_DISALLOW_COPY_AND_ASSIGN(EmbedderState); -}; - -void PlatformMacMain(std::string icu_data_path, - std::string application_library_path, - std::string bundle_path) { - static std::unique_ptr g_embedder; - static std::once_flag once_main; - - std::call_once(once_main, [&]() { - g_embedder = - WTF::MakeUnique(icu_data_path, application_library_path, bundle_path); - }); -} - -static bool FlagsValidForCommandLineLaunch(const std::string& bundle_path, - const std::string& main, - const std::string& packages) { - if (main.empty() || packages.empty() || bundle_path.empty()) { - return false; - } - - // Ensure that the paths exists. This catches cases where the user has - // successfully launched the application from the tooling but has since moved - // the source files on disk and is launching again directly. - - NSFileManager* manager = [NSFileManager defaultManager]; - - if (![manager fileExistsAtPath:@(main.c_str())]) { - return false; - } - - if (![manager fileExistsAtPath:@(packages.c_str())]) { - return false; - } - - if (![manager fileExistsAtPath:@(bundle_path.c_str())]) { - return false; - } - - return true; -} - -static std::string ResolveCommandLineLaunchFlag(const fxl::StringView name) { - const auto& command_line = shell::Shell::Shared().GetCommandLine(); - - std::string command_line_option; - if (command_line.GetOptionValue(name, &command_line_option)) { - return command_line_option; - } - - const char* saved_default = - [[NSUserDefaults standardUserDefaults] stringForKey:@(name.data())].UTF8String; - - if (saved_default != NULL) { - return saved_default; - } - - return ""; -} - -bool AttemptLaunchFromCommandLineSwitches(Engine* engine) { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - - const auto& command_line = shell::Shell::Shared().GetCommandLine(); - - if (command_line.HasOption(FlagForSwitch(Switch::FlutterAssetsDir)) || - command_line.HasOption(FlagForSwitch(Switch::MainDartFile)) || - command_line.HasOption(FlagForSwitch(Switch::Packages))) { - // The main dart file, Flutter assets directory and the package root must be - // specified in one go. We dont want to end up in a situation where we take - // one value from the command line and the others from user defaults. In - // case, any new flags are specified, forget about all the old ones. - [defaults removeObjectForKey:@(FlagForSwitch(Switch::FlutterAssetsDir).data())]; - [defaults removeObjectForKey:@(FlagForSwitch(Switch::MainDartFile).data())]; - [defaults removeObjectForKey:@(FlagForSwitch(Switch::Packages).data())]; - - [defaults synchronize]; - } - - std::string bundle_path = ResolveCommandLineLaunchFlag(FlagForSwitch(Switch::FlutterAssetsDir)); - std::string main = ResolveCommandLineLaunchFlag(FlagForSwitch(Switch::MainDartFile)); - std::string packages = ResolveCommandLineLaunchFlag(FlagForSwitch(Switch::Packages)); - - if (!FlagsValidForCommandLineLaunch(bundle_path, main, packages)) { - return false; - } - - // Save the newly resolved dart main file and the package root to user - // defaults so that the next time the user launches the application in the - // simulator without the tooling, the application boots up. - [defaults setObject:@(bundle_path.c_str()) - forKey:@(FlagForSwitch(Switch::FlutterAssetsDir).data())]; - [defaults setObject:@(main.c_str()) forKey:@(FlagForSwitch(Switch::MainDartFile).data())]; - [defaults setObject:@(packages.c_str()) forKey:@(FlagForSwitch(Switch::Packages).data())]; - - [defaults synchronize]; - - blink::Threads::UI()->PostTask([ engine = engine->GetWeakPtr(), bundle_path, main, packages ] { - if (engine) - engine->RunBundleAndSource(bundle_path, main, packages); - }); - - return true; -} - -} // namespace shell diff --git a/shell/platform/darwin/common/process_info_mac.cc b/shell/platform/darwin/common/process_info_mac.cc deleted file mode 100644 index 11f70f305a3e9..0000000000000 --- a/shell/platform/darwin/common/process_info_mac.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/shell/platform/darwin/common/process_info_mac.h" - -namespace shell { - -ProcessInfoMac::ProcessInfoMac() = default; - -ProcessInfoMac::~ProcessInfoMac() = default; - -bool ProcessInfoMac::SampleNow() { - mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT; - kern_return_t result = - task_info(mach_task_self(), // - MACH_TASK_BASIC_INFO, // - reinterpret_cast(&last_sample_), // - &size); - if (result == KERN_SUCCESS) { - return true; - } - - last_sample_ = {}; - return false; -} - -size_t ProcessInfoMac::GetVirtualMemorySize() { - return last_sample_.virtual_size; -} - -size_t ProcessInfoMac::GetResidentMemorySize() { - return last_sample_.resident_size; -} - -} // namespace shell diff --git a/shell/platform/darwin/common/process_info_mac.h b/shell/platform/darwin/common/process_info_mac.h deleted file mode 100644 index 7edc8034173e0..0000000000000 --- a/shell/platform/darwin/common/process_info_mac.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2016 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_SHELL_PLATFORM_DARWIN_COMMON_PROCESS_INFO_MAC_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_PROCESS_INFO_MAC_H_ - -#include -#include -#include -#include "flutter/flow/process_info.h" -#include "lib/fxl/macros.h" - -namespace shell { - -class ProcessInfoMac : public flow::ProcessInfo { - public: - ProcessInfoMac(); - - ~ProcessInfoMac(); - - bool SampleNow() override; - - size_t GetVirtualMemorySize() override; - - size_t GetResidentMemorySize() override; - - private: - struct mach_task_basic_info last_sample_; - - FXL_DISALLOW_COPY_AND_ASSIGN(ProcessInfoMac); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_PROCESS_INFO_MAC_H_ diff --git a/shell/platform/darwin/desktop/BUILD.gn b/shell/platform/darwin/desktop/BUILD.gn index a9c05f85ef284..5ec3298be4aa4 100644 --- a/shell/platform/darwin/desktop/BUILD.gn +++ b/shell/platform/darwin/desktop/BUILD.gn @@ -8,10 +8,8 @@ source_set("mac_desktop_platform") { visibility = [ ":*" ] sources = [ - "flutter_app_delegate.h", - "flutter_app_delegate.m", - "flutter_application.h", - "flutter_application.mm", + "flutter_application_delegate.h", + "flutter_application_delegate.mm", "flutter_window.h", "flutter_window.mm", "main_mac.mm", @@ -22,32 +20,22 @@ source_set("mac_desktop_platform") { ] deps = [ - "//third_party/dart/runtime:libdart_jit", "$flutter_root/common", "$flutter_root/fml", "$flutter_root/shell/common", "$flutter_root/shell/gpu", "$flutter_root/shell/platform/darwin/common", - "$flutter_root/shell/testing", "$flutter_root/synchronization", "//garnet/public/lib/fxl", + "//third_party/dart/runtime:libdart_jit", "//third_party/skia", + "//third_party/skia:gpu", ] - public_configs = [ - "$flutter_root:config", - ] -} - -executable("shell_standalone") { - output_name = "flutter_tester" - deps = [ - ":mac_desktop_platform", - ] + public_configs = [ "$flutter_root:config" ] } if (!is_fuchsia_host) { - import("//build/config/mac/rules.gni") resource_copy_mac("mac_desktop_resources") { diff --git a/shell/platform/darwin/desktop/Info.plist b/shell/platform/darwin/desktop/Info.plist index 31d3f1240db6b..048afb6dadca2 100644 --- a/shell/platform/darwin/desktop/Info.plist +++ b/shell/platform/darwin/desktop/Info.plist @@ -9,11 +9,11 @@ CFBundleIconFile CFBundleIdentifier - io.flutter + io.flutter.engine CFBundleInfoDictionaryVersion 6.0 CFBundleName - Flutter + Flutter Engine CFBundlePackageType APPL CFBundleShortVersionString @@ -26,9 +26,7 @@ 10.6 NSHumanReadableCopyright Copyright 2015 The Flutter Authors. All rights reserved. - NSMainNibFile - flutter_mac NSPrincipalClass - FlutterApplication + NSApplication diff --git a/shell/platform/darwin/desktop/flutter_app_delegate.h b/shell/platform/darwin/desktop/flutter_app_delegate.h deleted file mode 100644 index d6addcb17d0a4..0000000000000 --- a/shell/platform/darwin/desktop/flutter_app_delegate.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2015 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 __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APP_DELEGATE__ -#define __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APP_DELEGATE__ - -#import - -@interface FlutterAppDelegate : NSObject - -@end - -#endif /* defined(__SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APP_DELEGATE__) */ diff --git a/shell/platform/darwin/desktop/flutter_app_delegate.m b/shell/platform/darwin/desktop/flutter_app_delegate.m deleted file mode 100644 index 7e2dfd68389f8..0000000000000 --- a/shell/platform/darwin/desktop/flutter_app_delegate.m +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015 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. - -#import "flutter_app_delegate.h" - -@interface FlutterAppDelegate () - -@property(assign) IBOutlet NSWindow* window; - -@end - -@implementation FlutterAppDelegate - -@end diff --git a/shell/platform/darwin/desktop/flutter_application.mm b/shell/platform/darwin/desktop/flutter_application.mm deleted file mode 100644 index 57b1c83ba069a..0000000000000 --- a/shell/platform/darwin/desktop/flutter_application.mm +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2015 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. - -#include "flutter/shell/platform/darwin/desktop/flutter_application.h" - -@implementation FlutterApplication -@end diff --git a/shell/platform/darwin/desktop/flutter_application.h b/shell/platform/darwin/desktop/flutter_application_delegate.h similarity index 65% rename from shell/platform/darwin/desktop/flutter_application.h rename to shell/platform/darwin/desktop/flutter_application_delegate.h index 6a4167b5f273a..3995557b25e79 100644 --- a/shell/platform/darwin/desktop/flutter_application.h +++ b/shell/platform/darwin/desktop/flutter_application_delegate.h @@ -1,13 +1,14 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// 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_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_H_ +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ #import -@interface FlutterApplication : NSApplication +@interface FlutterApplicationDelegate : NSObject + @end -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_H_ +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ diff --git a/shell/platform/darwin/desktop/flutter_application_delegate.mm b/shell/platform/darwin/desktop/flutter_application_delegate.mm new file mode 100644 index 0000000000000..03076b848b25f --- /dev/null +++ b/shell/platform/darwin/desktop/flutter_application_delegate.mm @@ -0,0 +1,80 @@ +// 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/shell/platform/darwin/desktop/flutter_application_delegate.h" +#include "flutter/shell/platform/darwin/desktop/flutter_window.h" + +#include + +@implementation FlutterApplicationDelegate + +- (void)applicationWillFinishLaunching:(NSNotification*)notification { + [self configureMainMenuBar]; + [self onNewFlutterWindow:self]; +} + +- (void)configureMainMenuBar { + NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@"MainMenu"] autorelease]; + + NSMenuItem* engineItem = + [[[NSMenuItem alloc] initWithTitle:@"Engine" action:NULL keyEquivalent:@""] autorelease]; + + NSMenu* engineMenu = [[[NSMenu alloc] initWithTitle:@"EngineMenu"] autorelease]; + + NSMenuItem* newEngineItem = [[[NSMenuItem alloc] initWithTitle:@"New Engine" + action:@selector(onNewFlutterWindow:) + keyEquivalent:@""] autorelease]; + newEngineItem.keyEquivalent = @"n"; + newEngineItem.keyEquivalentModifierMask = NSCommandKeyMask; + + NSMenuItem* shutdownEngineItem = + [[[NSMenuItem alloc] initWithTitle:@"Shutdown Engine" + action:@selector(onShutdownFlutterWindow:) + keyEquivalent:@""] autorelease]; + shutdownEngineItem.keyEquivalent = @"w"; + shutdownEngineItem.keyEquivalentModifierMask = NSCommandKeyMask; + + NSMenuItem* quitItem = [[[NSMenuItem alloc] initWithTitle:@"Quit" + action:@selector(onQuitFlutterApplication:) + keyEquivalent:@""] autorelease]; + quitItem.keyEquivalent = @"q"; + quitItem.keyEquivalentModifierMask = NSCommandKeyMask; + + [mainMenu addItem:engineItem]; + [engineItem setSubmenu:engineMenu]; + [engineMenu addItem:newEngineItem]; + [engineMenu addItem:shutdownEngineItem]; + [engineMenu addItem:quitItem]; + + [NSApplication sharedApplication].mainMenu = mainMenu; +} + +- (void)onNewFlutterWindow:(id)sender { + FlutterWindow* window = [[FlutterWindow alloc] init]; + [window setReleasedWhenClosed:YES]; + + NSWindow* currentKeyWindow = [NSApplication sharedApplication].keyWindow; + + if (currentKeyWindow == nil) { + [window center]; + } else { + [window center]; + NSPoint currentWindowFrameOrigin = window.frame.origin; + currentWindowFrameOrigin.x = currentKeyWindow.frame.origin.x + 20; + currentWindowFrameOrigin.y = currentKeyWindow.frame.origin.y - 20; + [window setFrameOrigin:currentWindowFrameOrigin]; + } + + [window makeKeyAndOrderFront:sender]; +} + +- (void)onShutdownFlutterWindow:(id)sender { + [[NSApplication sharedApplication].keyWindow close]; +} + +- (void)onQuitFlutterApplication:(id)sender { + exit(0); +} + +@end diff --git a/shell/platform/darwin/desktop/flutter_mac.xib b/shell/platform/darwin/desktop/flutter_mac.xib deleted file mode 100644 index c02ab7912da5a..0000000000000 --- a/shell/platform/darwin/desktop/flutter_mac.xib +++ /dev/null @@ -1,695 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/shell/platform/darwin/desktop/flutter_window.h b/shell/platform/darwin/desktop/flutter_window.h index 851535ba38e9e..e07fe4eeb7520 100644 --- a/shell/platform/darwin/desktop/flutter_window.h +++ b/shell/platform/darwin/desktop/flutter_window.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW__ -#define __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW__ +#ifndef SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ +#define SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ #import @@ -11,4 +11,4 @@ @end -#endif /* defined(__SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW__) */ +#endif // SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ diff --git a/shell/platform/darwin/desktop/flutter_window.mm b/shell/platform/darwin/desktop/flutter_window.mm index ca080e9275742..4c87200fb3856 100644 --- a/shell/platform/darwin/desktop/flutter_window.mm +++ b/shell/platform/darwin/desktop/flutter_window.mm @@ -2,16 +2,25 @@ // 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 + #import "flutter_window.h" -#include "flutter/common/threads.h" +#include + +#include "flutter/common/task_runners.h" +#include "flutter/fml/message_loop.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/switches.h" +#include "flutter/shell/common/thread_host.h" #include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/shell/platform/darwin/common/command_line.h" #include "flutter/shell/platform/darwin/desktop/platform_view_mac.h" +#include "lib/fxl/functional/make_copyable.h" -@interface FlutterWindow () +@interface FlutterWindow () -@property(assign) IBOutlet NSOpenGLView* renderSurface; -@property(getter=isSurfaceSetup) BOOL surfaceSetup; +@property(strong) NSOpenGLView* renderSurface; @end @@ -37,34 +46,130 @@ @interface FlutterWindow () } @implementation FlutterWindow { - std::shared_ptr _platformView; + shell::ThreadHost _thread_host; + std::unique_ptr _shell; bool _mouseIsDown; } -@synthesize renderSurface = _renderSurface; -@synthesize surfaceSetup = _surfaceSetup; +- (instancetype)init { + self = + [super initWithContentRect:NSMakeRect(10.0, 10.0, 800.0, 600.0) + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + if (self) { + self.delegate = self; + [self setupRenderSurface]; + [self setupShell]; + [self updateWindowSize]; + } + + return self; +} + +- (void)setupRenderSurface { + NSOpenGLView* renderSurface = [[[NSOpenGLView alloc] init] autorelease]; + const NSOpenGLPixelFormatAttribute attrs[] = { + NSOpenGLPFADoubleBuffer, // + NSOpenGLPFAAllowOfflineRenderers, // + 0 // + }; + renderSurface.pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs] autorelease]; + renderSurface.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + renderSurface.frame = + NSMakeRect(0.0, 0.0, self.contentView.bounds.size.width, self.contentView.bounds.size.height); + [self.contentView addSubview:renderSurface]; + self.renderSurface = renderSurface; +} -- (void)awakeFromNib { - [super awakeFromNib]; +static std::string CreateThreadLabel() { + std::stringstream stream; + static int index = 1; + stream << "io.flutter." << index++; + return stream.str(); +} - self.delegate = self; +- (void)setupShell { + FXL_DCHECK(!_shell) << "The shell must not already be set."; - [self updateWindowSize]; + auto thread_label = CreateThreadLabel(); + + // Create the threads on which to run the shell. + _thread_host = {thread_label, shell::ThreadHost::Type::GPU | shell::ThreadHost::Type::UI | + shell::ThreadHost::Type::IO}; + + // Grab the task runners for the newly created threads. + fml::MessageLoop::EnsureInitializedForCurrentThread(); + blink::TaskRunners task_runners(thread_label, // label + fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform + _thread_host.gpu_thread->GetTaskRunner(), // GPU + _thread_host.ui_thread->GetTaskRunner(), // UI + _thread_host.io_thread->GetTaskRunner() // IO + ); + + // Figure out the settings from the command line arguments. + auto settings = shell::SettingsFromCommandLine(shell::CommandLineFromNSProcessInfo()); + + if (settings.icu_data_path.size() == 0) { + settings.icu_data_path = + [[NSBundle mainBundle] pathForResource:@"icudtl.dat" ofType:@""].UTF8String; + } + + settings.using_blink = false; + + settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { + fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); + }; + + settings.task_observer_remove = [](intptr_t key) { + fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); + }; + + // Setup the callback that will be run on the appropriate threads. + shell::Shell::CreateCallback on_create_platform_view = + [render_surface = self.renderSurface](shell::Shell& shell) { + return std::make_unique(shell, render_surface); + }; + + shell::Shell::CreateCallback on_create_rasterizer = [](shell::Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }; + + // Finally, create the shell. + _shell = shell::Shell::Create(std::move(task_runners), settings, on_create_platform_view, + on_create_rasterizer); + + // Launch the engine with the inferred run configuration. + _shell->GetTaskRunners().GetUITaskRunner()->PostTask(fxl::MakeCopyable( + [engine = _shell->GetEngine(), + config = shell::RunConfiguration::InferFromSettings(_shell->GetSettings())]() mutable { + if (engine) { + auto result = engine->Run(std::move(config)); + if (!result) { + FXL_LOG(ERROR) << "Could not launch the engine with configuration."; + } + } + })); + + [self notifySurfaceCreated]; } -- (void)setupPlatformView { - FXL_DCHECK(_platformView == nullptr) << "The platform view must not already be set."; +- (void)notifySurfaceCreated { + if (!_shell || !_shell->IsSetup()) { + return; + } - _platformView = std::make_shared(self.renderSurface); - _platformView->Attach(); - _platformView->SetupResourceContextOnIOThread(); - _platformView->NotifyCreated(std::make_unique(_platformView.get())); + // Tell the platform view that it has a GL surface. + _shell->GetPlatformView()->NotifyCreated(); } -// TODO(eseidel): This does not belong in flutter_window! -// Probably belongs in NSApplicationDelegate didFinishLaunching. -- (void)setupAndLoadDart { - _platformView->SetupAndLoadDart(); +- (void)notifySurfaceDestroyed { + if (!_shell || !_shell->IsSetup()) { + return; + } + + // Tell the platform view that its surface is about to be lost. + _shell->GetPlatformView()->NotifyDestroyed(); } - (void)windowDidResize:(NSNotification*)notification { @@ -72,34 +177,28 @@ - (void)windowDidResize:(NSNotification*)notification { } - (void)updateWindowSize { - [self setupSurfaceIfNecessary]; + if (!_shell) { + return; + } blink::ViewportMetrics metrics; auto size = self.renderSurface.frame.size; metrics.physical_width = size.width; metrics.physical_height = size.height; - - blink::Threads::UI()->PostTask([ engine = _platformView->engine().GetWeakPtr(), metrics ] { - if (engine.get()) { + _shell->GetTaskRunners().GetUITaskRunner()->PostTask([engine = _shell->GetEngine(), metrics]() { + if (engine) { engine->SetViewportMetrics(metrics); } }); } -- (void)setupSurfaceIfNecessary { - if (self.isSurfaceSetup) { - return; - } - - self.surfaceSetup = YES; - - [self setupPlatformView]; - [self setupAndLoadDart]; -} - #pragma mark - Responder overrides - (void)dispatchEvent:(NSEvent*)event phase:(NSEventPhase)phase { + if (!_shell) { + return; + } + NSPoint location = [_renderSurface convertPoint:event.locationInWindow fromView:nil]; location.y = _renderSurface.frame.size.height - location.y; @@ -134,13 +233,14 @@ - (void)dispatchEvent:(NSEvent*)event phase:(NSEventPhase)phase { break; } - blink::Threads::UI()->PostTask([ engine = _platformView->engine().GetWeakPtr(), pointer_data ] { - if (engine.get()) { - blink::PointerDataPacket packet(1); - packet.SetPointerData(0, pointer_data); - engine->DispatchPointerDataPacket(packet); - } - }); + _shell->GetTaskRunners().GetUITaskRunner()->PostTask( + [engine = _shell->GetEngine(), pointer_data] { + if (engine) { + blink::PointerDataPacket packet(1); + packet.SetPointerData(0, pointer_data); + engine->DispatchPointerDataPacket(packet); + } + }); } - (void)mouseDown:(NSEvent*)event { @@ -155,11 +255,18 @@ - (void)mouseUp:(NSEvent*)event { [self dispatchEvent:event phase:NSEventPhaseEnded]; } -- (void)dealloc { - if (_platformView) { - _platformView->NotifyDestroyed(); - } +- (void)reset { + [self notifySurfaceDestroyed]; + _shell.reset(); + _thread_host.Reset(); +} +- (void)windowWillClose:(NSNotification*)notification { + [self reset]; +} + +- (void)dealloc { + [self reset]; [super dealloc]; } diff --git a/shell/platform/darwin/desktop/main_mac.mm b/shell/platform/darwin/desktop/main_mac.mm index 808a5f63f1d14..edd08d0c8b783 100644 --- a/shell/platform/darwin/desktop/main_mac.mm +++ b/shell/platform/darwin/desktop/main_mac.mm @@ -7,91 +7,20 @@ #include #include "flutter/fml/message_loop.h" -#include "flutter/shell/common/platform_view.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/switches.h" -#include "flutter/shell/platform/darwin/common/platform_mac.h" -#include "flutter/shell/platform/darwin/desktop/flutter_application.h" -#include "flutter/shell/testing/test_runner.h" -#include "flutter/shell/testing/testing.h" +#include "flutter/shell/platform/darwin/desktop/flutter_application_delegate.h" #include "lib/fxl/command_line.h" #include "lib/fxl/logging.h" -#include "lib/tonic/dart_microtask_queue.h" -// Exit codes used by the Dart command line tool. -const int kApiErrorExitCode = 253; -const int kCompilationErrorExitCode = 254; -const int kErrorExitCode = 255; - -// Checks whether the engine's main Dart isolate has no pending work. If so, -// then exit the given message loop. -class ScriptCompletionTaskObserver : public fml::TaskObserver { - public: - ScriptCompletionTaskObserver(fxl::RefPtr task_runner) - : main_task_runner_(std::move(task_runner)), - prev_live_(false), - last_error_(tonic::kNoError) {} - - void DidProcessTask() override { - shell::TestRunner& test_runner = shell::TestRunner::Shared(); - shell::Engine& engine = test_runner.platform_view().engine(); - - if (engine.GetLoadScriptError() != tonic::kNoError) { - last_error_ = engine.GetLoadScriptError(); - main_task_runner_->PostTask([]() { fml::MessageLoop::GetCurrent().Terminate(); }); - return; - } - - bool live = engine.UIIsolateHasLivePorts(); - if (prev_live_ && !live) { - last_error_ = engine.GetUIIsolateLastError(); - main_task_runner_->PostTask([]() { fml::MessageLoop::GetCurrent().Terminate(); }); - } - prev_live_ = live; - } - - tonic::DartErrorHandleType last_error() { return last_error_; } - - private: - fxl::RefPtr main_task_runner_; - bool prev_live_; - tonic::DartErrorHandleType last_error_; -}; - -int ConvertErrorTypeToExitCode(tonic::DartErrorHandleType error) { - switch (error) { - case tonic::kCompilationErrorType: - return kCompilationErrorExitCode; - case tonic::kApiErrorType: - return kApiErrorExitCode; - case tonic::kUnknownErrorType: - return kErrorExitCode; - default: - return 0; - } -} - -static fxl::CommandLine InitializedCommandLine() { +int main(int argc, const char* argv[]) { std::vector args_vector; for (NSString* arg in [NSProcessInfo processInfo].arguments) { args_vector.emplace_back(arg.UTF8String); } - return fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); -} - -int main(int argc, const char* argv[]) { - [FlutterApplication sharedApplication]; - - // Can't use shell::Shell::Shared().GetCommandLine() because it is initialized only - // in shell::PlatformMacMain call below. - auto command_line = InitializedCommandLine(); - - std::string bundle_path = ""; - command_line.GetOptionValue(FlagForSwitch(shell::Switch::FlutterAssetsDir), &bundle_path); - - shell::PlatformMacMain("", "", bundle_path); + auto command_line = fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); // Print help. if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { @@ -99,36 +28,7 @@ int main(int argc, const char* argv[]) { return EXIT_SUCCESS; } - // Decide between interactive and non-interactive modes. - if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::NonInteractive))) { - if (!shell::InitForTesting(std::move(command_line))) - return 1; - - // Note that this task observer must be added after the observer that drains - // the microtask queue. - ScriptCompletionTaskObserver task_observer(fml::MessageLoop::GetCurrent().GetTaskRunner()); - blink::Threads::UI()->PostTask( - [&task_observer] { fml::MessageLoop::GetCurrent().AddTaskObserver(&task_observer); }); - - fml::MessageLoop::GetCurrent().Run(); - - shell::TestRunner& test_runner = shell::TestRunner::Shared(); - tonic::DartErrorHandleType error = test_runner.platform_view().engine().GetLoadScriptError(); - if (error == tonic::kNoError) - error = task_observer.last_error(); - if (error == tonic::kNoError) { - fxl::AutoResetWaitableEvent latch; - blink::Threads::UI()->PostTask([&error, &latch] { - error = tonic::DartMicrotaskQueue::GetForCurrentThread()->GetLastError(); - latch.Signal(); - }); - latch.Wait(); - } - - // The script has completed and the engine may not be in a clean state, - // so just stop the process. - exit(ConvertErrorTypeToExitCode(error)); - } else { - return NSApplicationMain(argc, argv); - } + [NSApplication sharedApplication].delegate = + [[[FlutterApplicationDelegate alloc] init] autorelease]; + return NSApplicationMain(argc, argv); } diff --git a/shell/platform/darwin/desktop/platform_view_mac.h b/shell/platform/darwin/desktop/platform_view_mac.h index 501400b6803d4..d4b19b94d1d99 100644 --- a/shell/platform/darwin/desktop/platform_view_mac.h +++ b/shell/platform/darwin/desktop/platform_view_mac.h @@ -7,6 +7,7 @@ #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/shell.h" #include "flutter/shell/gpu/gpu_surface_gl.h" #include "lib/fxl/memory/weak_ptr.h" @@ -15,15 +16,13 @@ namespace shell { -class PlatformViewMac : public PlatformView, public GPUSurfaceGLDelegate { +class PlatformViewMac final : public PlatformView, public GPUSurfaceGLDelegate { public: - PlatformViewMac(NSOpenGLView* gl_view); + PlatformViewMac(Shell& shell, NSOpenGLView* gl_view); ~PlatformViewMac() override; - virtual void Attach() override; - - void SetupAndLoadDart(); + std::unique_ptr CreateVSyncWaiter() override; bool GLContextMakeCurrent() override; @@ -33,27 +32,17 @@ class PlatformViewMac : public PlatformView, public GPUSurfaceGLDelegate { intptr_t GLContextFBO() const override; - VsyncWaiter* GetVsyncWaiter() override; - - bool ResourceContextMakeCurrent() override; - - void RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) override; - - void SetAssetBundlePath(const std::string& assets_directory) override; - private: fml::scoped_nsobject opengl_view_; fml::scoped_nsobject resource_loading_context_; bool IsValid() const; - void SetupAndLoadFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages); + // |shell::PlatformView| + std::unique_ptr CreateRenderingSurface() override; - void SetAssetBundlePathOnUI(const std::string& assets_directory); + // |shell::PlatformView| + sk_sp CreateResourceContext() const override; FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewMac); }; diff --git a/shell/platform/darwin/desktop/platform_view_mac.mm b/shell/platform/darwin/desktop/platform_view_mac.mm index 42948386fbcd4..f25fa6945af23 100644 --- a/shell/platform/darwin/desktop/platform_view_mac.mm +++ b/shell/platform/darwin/desktop/platform_view_mac.mm @@ -7,77 +7,26 @@ #include #include -#include "flutter/common/threads.h" #include "flutter/fml/trace_event.h" +#include "flutter/shell/common/io_manager.h" +#include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/switches.h" -#include "flutter/shell/gpu/gpu_rasterizer.h" -#include "flutter/shell/platform/darwin/common/platform_mac.h" -#include "flutter/shell/platform/darwin/common/process_info_mac.h" #include "flutter/shell/platform/darwin/desktop/vsync_waiter_mac.h" #include "lib/fxl/command_line.h" #include "lib/fxl/synchronization/waitable_event.h" namespace shell { -PlatformViewMac::PlatformViewMac(NSOpenGLView* gl_view) - : PlatformView(std::make_unique(std::make_unique())), +PlatformViewMac::PlatformViewMac(Shell& shell, NSOpenGLView* gl_view) + : PlatformView(shell, shell.GetTaskRunners()), opengl_view_([gl_view retain]), resource_loading_context_([[NSOpenGLContext alloc] initWithFormat:gl_view.pixelFormat shareContext:gl_view.openGLContext]) {} PlatformViewMac::~PlatformViewMac() = default; -void PlatformViewMac::Attach() { - CreateEngine(); -} - -void PlatformViewMac::SetupAndLoadDart() { - if (AttemptLaunchFromCommandLineSwitches(&engine())) { - // This attempts launching from a Flutter assets directory that does not - // contain a dart snapshot. - return; - } - - const auto& command_line = shell::Shell::Shared().GetCommandLine(); - - std::string bundle_path = - command_line.GetOptionValueWithDefault(FlagForSwitch(Switch::FlutterAssetsDir), ""); - if (!bundle_path.empty()) { - blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), bundle_path ] { - if (engine) - engine->RunBundle(bundle_path); - }); - return; - } - - auto args = command_line.positional_args(); - if (args.size() > 0) { - std::string main = args[0]; - std::string packages = - command_line.GetOptionValueWithDefault(FlagForSwitch(Switch::Packages), ""); - blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), main, packages ] { - if (engine) - engine->RunBundleAndSource(std::string(), main, packages); - }); - return; - } -} - -void PlatformViewMac::SetupAndLoadFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) { - blink::Threads::UI()->PostTask( - [ engine = engine().GetWeakPtr(), assets_directory, main, packages ] { - if (engine) - engine->RunBundleAndSource(assets_directory, main, packages); - }); -} - -void PlatformViewMac::SetAssetBundlePathOnUI(const std::string& assets_directory) { - blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), assets_directory ] { - if (engine) - engine->SetAssetBundlePath(assets_directory); - }); +std::unique_ptr PlatformViewMac::CreateVSyncWaiter() { + return std::make_unique(task_runners_); } intptr_t PlatformViewMac::GLContextFBO() const { @@ -115,21 +64,9 @@ return true; } -VsyncWaiter* PlatformViewMac::GetVsyncWaiter() { - if (!vsync_waiter_) - vsync_waiter_ = std::make_unique(); - return vsync_waiter_.get(); -} - -bool PlatformViewMac::ResourceContextMakeCurrent() { - NSOpenGLContext* context = resource_loading_context_.get(); - - if (context == nullptr) { - return false; - } - - [context makeCurrentContext]; - return true; +sk_sp PlatformViewMac::CreateResourceContext() const { + [resource_loading_context_.get() makeCurrentContext]; + return IOManager::CreateCompatibleResourceLoadingContext(GrBackend::kOpenGL_GrBackend); } bool PlatformViewMac::IsValid() const { @@ -146,30 +83,8 @@ return true; } -void PlatformViewMac::RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) { - auto latch = new fxl::ManualResetWaitableEvent(); - - dispatch_async(dispatch_get_main_queue(), ^{ - SetupAndLoadFromSource(assets_directory, main, packages); - latch->Signal(); - }); - - latch->Wait(); - delete latch; -} - -void PlatformViewMac::SetAssetBundlePath(const std::string& assets_directory) { - auto latch = new fxl::ManualResetWaitableEvent(); - - dispatch_async(dispatch_get_main_queue(), ^{ - SetAssetBundlePathOnUI(assets_directory); - latch->Signal(); - }); - - latch->Wait(); - delete latch; +std::unique_ptr PlatformViewMac::CreateRenderingSurface() { + return std::make_unique(this); } } // namespace shell diff --git a/shell/platform/darwin/desktop/vsync_waiter_mac.cc b/shell/platform/darwin/desktop/vsync_waiter_mac.cc index a28ff62edb918..0ccadaf42754d 100644 --- a/shell/platform/darwin/desktop/vsync_waiter_mac.cc +++ b/shell/platform/darwin/desktop/vsync_waiter_mac.cc @@ -6,14 +6,14 @@ #include -#include "flutter/common/threads.h" #include "lib/fxl/logging.h" namespace shell { #define link_ (reinterpret_cast(opaque_)) -VsyncWaiterMac::VsyncWaiterMac() : opaque_(nullptr) { +VsyncWaiterMac::VsyncWaiterMac(blink::TaskRunners task_runners) + : VsyncWaiter(std::move(task_runners)), opaque_(nullptr) { // Create the link. CVDisplayLinkRef link = nullptr; CVDisplayLinkCreateWithActiveCGDisplays(&link); @@ -48,18 +48,10 @@ void VsyncWaiterMac::OnDisplayLink() { CVDisplayLinkStop(link_); - auto callback = std::move(callback_); - callback_ = Callback(); - - blink::Threads::UI()->PostTask( - [callback, frame_start_time, frame_target_time] { - callback(frame_start_time, frame_target_time); - }); + FireCallback(frame_start_time, frame_target_time); } -void VsyncWaiterMac::AsyncWaitForVsync(Callback callback) { - FXL_DCHECK(!callback_); - callback_ = std::move(callback); +void VsyncWaiterMac::AwaitVSync() { CVDisplayLinkStart(link_); } diff --git a/shell/platform/darwin/desktop/vsync_waiter_mac.h b/shell/platform/darwin/desktop/vsync_waiter_mac.h index 15f551f212901..0ad929a509ea3 100644 --- a/shell/platform/darwin/desktop/vsync_waiter_mac.h +++ b/shell/platform/darwin/desktop/vsync_waiter_mac.h @@ -10,19 +10,19 @@ namespace shell { -class VsyncWaiterMac : public VsyncWaiter { +class VsyncWaiterMac final : public VsyncWaiter { public: - VsyncWaiterMac(); + VsyncWaiterMac(blink::TaskRunners task_runners); ~VsyncWaiterMac() override; - void AsyncWaitForVsync(Callback callback) override; - private: void* opaque_; - Callback callback_; + + void AwaitVSync() override; static void OnDisplayLink(void* context); + void OnDisplayLink(); FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterMac); diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 310af79c2ed8e..8946ee954c23a 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -40,8 +40,6 @@ shared_library("create_flutter_framework_dylib") { "framework/Source/FlutterDartProject.mm", "framework/Source/FlutterDartProject_Internal.h", "framework/Source/FlutterHeadlessDartRunner.mm", - "framework/Source/FlutterDartSource.h", - "framework/Source/FlutterDartSource.mm", "framework/Source/FlutterNavigationController.mm", "framework/Source/FlutterPlatformPlugin.h", "framework/Source/FlutterPlatformPlugin.mm", @@ -53,14 +51,15 @@ shared_library("create_flutter_framework_dylib") { "framework/Source/FlutterView.h", "framework/Source/FlutterView.mm", "framework/Source/FlutterViewController.mm", + "framework/Source/FlutterViewController_Internal.h", "framework/Source/accessibility_bridge.h", "framework/Source/accessibility_bridge.mm", "framework/Source/accessibility_text_entry.h", "framework/Source/accessibility_text_entry.mm", - "framework/Source/flutter_main_ios.h", - "framework/Source/flutter_main_ios.mm", "framework/Source/flutter_touch_mapper.h", "framework/Source/flutter_touch_mapper.mm", + "framework/Source/platform_message_response_darwin.h", + "framework/Source/platform_message_response_darwin.mm", "framework/Source/platform_message_router.h", "framework/Source/platform_message_router.mm", "framework/Source/vsync_waiter_ios.h", @@ -86,6 +85,7 @@ shared_library("create_flutter_framework_dylib") { "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/lib/ui", + "$flutter_root/runtime", "$flutter_root/shell/common", "$flutter_root/shell/gpu", "$flutter_root/shell/platform/darwin/common", @@ -95,7 +95,10 @@ shared_library("create_flutter_framework_dylib") { "//third_party/skia", ] if (flutter_runtime_mode == "debug") { - deps += [ "//third_party/dart/runtime:libdart_jit" ] + deps += [ + "$flutter_root/lib/snapshot", + "//third_party/dart/runtime:libdart_jit", + ] } else { deps += [ "//third_party/dart/runtime:libdart_precompiled_runtime" ] } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm index d5f30d02664d9..3c613c9fbad8f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm @@ -2,42 +2,121 @@ // 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/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" +#include "flutter/fml/message_loop.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/runtime/dart_vm.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/switches.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h" -#include "lib/fxl/strings/string_view.h" -#include "third_party/dart/runtime/include/dart_api.h" - -static NSURL* URLForSwitch(const fxl::StringView name) { - const auto& cmd = shell::Shell::Shared().GetCommandLine(); - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - - std::string switch_value; - if (cmd.GetOptionValue(name, &switch_value)) { - auto url = [NSURL fileURLWithPath:@(switch_value.c_str())]; - [defaults setURL:url forKey:@(name.data())]; - [defaults synchronize]; - return url; +#include "flutter/shell/platform/darwin/common/command_line.h" +#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" + +static const char* kScriptSnapshotFileName = "snapshot_blob.bin"; +static const char* kVMKernelSnapshotFileName = "platform.dill"; +static const char* kApplicationKernelSnapshotFileName = "kernel_blob.bin"; + +static blink::Settings DefaultSettingsForProcess() { + auto command_line = shell::CommandLineFromNSProcessInfo(); + + // Settings passed in explicitly via command line arguments take priority. + auto settings = shell::SettingsFromCommandLine(command_line); + + settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { + fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); + }; + + settings.task_observer_remove = [](intptr_t key) { + fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); + }; + + // The command line arguments may not always be complete. If they aren't, attempt to fill in + // defaults. + + // Flutter ships the ICU data file in the the bundle of the engine. Look for it there. + if (settings.icu_data_path.size() == 0) { + NSBundle* bundle = [NSBundle bundleForClass:[FlutterViewController class]]; + NSString* icuDataPath = [bundle pathForResource:@"icudtl" ofType:@"dat"]; + if (icuDataPath.length > 0) { + settings.icu_data_path = icuDataPath.UTF8String; + } } - return [defaults URLForKey:@(name.data())]; -} + if (blink::DartVM::IsRunningPrecompiledCode()) { + // The application bundle could be specified in the Info.plist. + if (settings.application_library_path.size() == 0) { + NSString* libraryName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTLibraryPath"]; + NSString* libraryPath = [[NSBundle mainBundle] pathForResource:libraryName ofType:nil]; + if (libraryPath.length > 0) { + settings.application_library_path = + [NSBundle bundleWithPath:libraryPath].executablePath.UTF8String; + } + } -@implementation FlutterDartProject { - NSBundle* _precompiledDartBundle; - FlutterDartSource* _dartSource; + // In case the application bundle is still not specified, look for the App.framework in the + // Frameworks directory. + if (settings.application_library_path.size() == 0) { + NSString* applicationFrameworkPath = + [[NSBundle mainBundle] pathForResource:@"Frameworks/App.framework" ofType:@""]; + if (applicationFrameworkPath.length > 0) { + settings.application_library_path = + [NSBundle bundleWithPath:applicationFrameworkPath].executablePath.UTF8String; + } + } + } - VMType _vmTypeRequirement; + // Checks to see if the flutter assets directory is already present. + if (settings.assets_path.size() == 0) { + NSString* assetsPath = [[NSBundle mainBundle] pathForResource:@"flutter_assets" ofType:@""]; + + if (assetsPath.length > 0) { + settings.assets_path = assetsPath.UTF8String; + + if (!blink::DartVM::IsRunningPrecompiledCode()) { + // Looking for the various script and kernel snapshot buffers only makes sense if we have a + // VM that can use these buffers. + { + // Check if there is a script snapshot in the assets directory we could potentially use. + NSURL* scriptSnapshotURL = [NSURL URLWithString:@(kScriptSnapshotFileName) + relativeToURL:[NSURL fileURLWithPath:assetsPath]]; + if ([[NSFileManager defaultManager] fileExistsAtPath:scriptSnapshotURL.path]) { + settings.script_snapshot_path = scriptSnapshotURL.path.UTF8String; + } + } + + { + // Check if there is a VM kernel snapshot in the assets directory we could potentially + // use. + NSURL* vmKernelSnapshotURL = [NSURL URLWithString:@(kVMKernelSnapshotFileName) + relativeToURL:[NSURL fileURLWithPath:assetsPath]]; + if ([[NSFileManager defaultManager] fileExistsAtPath:vmKernelSnapshotURL.path]) { + settings.kernel_snapshot_path = vmKernelSnapshotURL.path.UTF8String; + } + } + + { + // Check if there is an application kernel snapshot in the assets directory we could + // potentially use. + NSURL* applicationKernelSnapshotURL = + [NSURL URLWithString:@(kApplicationKernelSnapshotFileName) + relativeToURL:[NSURL fileURLWithPath:assetsPath]]; + if ([[NSFileManager defaultManager] fileExistsAtPath:applicationKernelSnapshotURL.path]) { + settings.application_kernel_asset = applicationKernelSnapshotURL.path.UTF8String; + } + } + } + } + } + + return settings; } -+ (void)initialize { - if (self == [FlutterDartProject class]) { - shell::FlutterMain(); - } +@implementation FlutterDartProject { + fml::scoped_nsobject _precompiledDartBundle; + blink::Settings _settings; } #pragma mark - Override base class designated initializers @@ -52,9 +131,16 @@ - (instancetype)initWithPrecompiledDartBundle:(NSBundle*)bundle { self = [super init]; if (self) { - _precompiledDartBundle = [bundle retain]; + _precompiledDartBundle.reset([bundle retain]); - [self checkReadiness]; + _settings = DefaultSettingsForProcess(); + + if (bundle != nil) { + NSString* executablePath = _precompiledDartBundle.get().executablePath; + if ([[NSFileManager defaultManager] fileExistsAtPath:executablePath]) { + _settings.application_library_path = executablePath.UTF8String; + } + } } return self; @@ -66,11 +152,15 @@ - (instancetype)initWithFlutterAssets:(NSURL*)flutterAssetsURL self = [super init]; if (self) { - _dartSource = [[FlutterDartSource alloc] initWithDartMain:dartMainURL - packages:dartPackages - flutterAssets:flutterAssetsURL]; + _settings = DefaultSettingsForProcess(); - [self checkReadiness]; + if ([[NSFileManager defaultManager] fileExistsAtPath:dartMainURL.path]) { + _settings.main_dart_file_path = dartMainURL.path.UTF8String; + } + + if ([[NSFileManager defaultManager] fileExistsAtPath:dartPackages.path]) { + _settings.packages_file_path = dartPackages.path.UTF8String; + } } return self; @@ -80,10 +170,17 @@ - (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssetsURL self = [super init]; if (self) { - _dartSource = - [[FlutterDartSource alloc] initWithFlutterAssetsWithScriptSnapshot:flutterAssetsURL]; + _settings = DefaultSettingsForProcess(); - [self checkReadiness]; + if ([[NSFileManager defaultManager] fileExistsAtPath:flutterAssetsURL.path]) { + _settings.assets_path = flutterAssetsURL.path.UTF8String; + + NSURL* scriptSnapshotPath = + [NSURL URLWithString:@(kScriptSnapshotFileName) relativeToURL:flutterAssetsURL]; + if ([[NSFileManager defaultManager] fileExistsAtPath:scriptSnapshotPath.path]) { + _settings.script_snapshot_path = scriptSnapshotPath.path.UTF8String; + } + } } return self; @@ -92,56 +189,19 @@ - (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssetsURL #pragma mark - Convenience initializers - (instancetype)initFromDefaultSourceForConfiguration { - NSBundle* bundle = [NSBundle mainBundle]; - - if (Dart_IsPrecompiledRuntime()) { - // Load from an AOTC snapshot. - return [self initWithPrecompiledDartBundle:bundle]; + if (blink::DartVM::IsRunningPrecompiledCode()) { + return [self initWithPrecompiledDartBundle:nil]; } else { - // Load directly from sources if the appropriate command line flags are - // specified. If not, try loading from a script snapshot in the framework - // bundle. - NSURL* flutterAssetsURL = URLForSwitch(shell::FlagForSwitch(shell::Switch::FlutterAssetsDir)); - - if (flutterAssetsURL == nil) { - // If the URL was not specified on the command line, look inside the - // FlutterApplication bundle. - NSString* flutterAssetsPath = [FlutterDartProject pathForFlutterAssetsFromBundle:bundle]; - if (flutterAssetsPath != nil) { - flutterAssetsURL = [NSURL fileURLWithPath:flutterAssetsPath isDirectory:NO]; - } - } - - if (flutterAssetsURL == nil) { - NSLog(@"Error: flutterAssets directory not present in bundle; unable to start app."); - [self release]; - return nil; - } - - NSURL* dartMainURL = URLForSwitch(shell::FlagForSwitch(shell::Switch::MainDartFile)); - NSURL* dartPackagesURL = URLForSwitch(shell::FlagForSwitch(shell::Switch::Packages)); - - return - [self initWithFlutterAssets:flutterAssetsURL dartMain:dartMainURL packages:dartPackagesURL]; + return [self initWithFlutterAssets:nil dartMain:nil packages:nil]; } - - NSAssert(NO, @"Unreachable"); - [self release]; - return nil; } -#pragma mark - Common initialization tasks - -- (void)checkReadiness { - if (_precompiledDartBundle != nil) { - _vmTypeRequirement = VMTypePrecompilation; - return; - } +- (const blink::Settings&)settings { + return _settings; +} - if (_dartSource != nil) { - _vmTypeRequirement = VMTypeInterpreter; - return; - } +- (shell::RunConfiguration)runConfiguration { + return shell::RunConfiguration::InferFromSettings(_settings); } #pragma mark - Assets-related utilities @@ -161,7 +221,7 @@ + (NSString*)pathForFlutterAssetsFromBundle:(NSBundle*)bundle { } + (NSString*)lookupKeyForAsset:(NSString*)asset { - NSString* flutterAssetsName = [FlutterDartProject flutterAssetsName: [NSBundle mainBundle]]; + NSString* flutterAssetsName = [FlutterDartProject flutterAssetsName:[NSBundle mainBundle]]; return [NSString stringWithFormat:@"%@/%@", flutterAssetsName, asset]; } @@ -169,179 +229,4 @@ + (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package { return [self lookupKeyForAsset:[NSString stringWithFormat:@"packages/%@/%@", package, asset]]; } -#pragma mark - Launching the project in a preconfigured engine. - -static NSString* NSStringFromVMType(VMType type) { - switch (type) { - case VMTypeInvalid: - return @"Invalid"; - case VMTypeInterpreter: - return @"Interpreter"; - case VMTypePrecompilation: - return @"Precompilation"; - } - - return @"Unknown"; -} - -- (void)launchInEngine:(shell::Engine*)engine - withEntrypoint:(NSString*)entrypoint - embedderVMType:(VMType)embedderVMType - result:(LaunchResult)result { - if (_vmTypeRequirement == VMTypeInvalid) { - result(NO, @"The Dart project is invalid and cannot be loaded by any VM."); - return; - } - - if (embedderVMType == VMTypeInvalid) { - result(NO, @"The embedder is invalid."); - return; - } - - if (_vmTypeRequirement != embedderVMType) { - NSString* message = - [NSString stringWithFormat: - @"Could not load the project because of differing project type. " - @"The project can run in '%@' but the embedder is configured as " - @"'%@'", - NSStringFromVMType(_vmTypeRequirement), NSStringFromVMType(embedderVMType)]; - result(NO, message); - return; - } - - switch (_vmTypeRequirement) { - case VMTypeInterpreter: - [self runFromSourceInEngine:engine withEntrypoint:entrypoint result:result]; - return; - case VMTypePrecompilation: - [self runFromPrecompiledSourceInEngine:engine withEntrypoint:entrypoint result:result]; - return; - case VMTypeInvalid: - break; - } - - return result(NO, @"Internal error"); -} - -- (void)launchInEngine:(shell::Engine*)engine - embedderVMType:(VMType)embedderVMType - result:(LaunchResult)result { - if (_vmTypeRequirement == VMTypeInvalid) { - result(NO, @"The Dart project is invalid and cannot be loaded by any VM."); - return; - } - - if (embedderVMType == VMTypeInvalid) { - result(NO, @"The embedder is invalid."); - return; - } - - if (_vmTypeRequirement != embedderVMType) { - NSString* message = - [NSString stringWithFormat: - @"Could not load the project because of differing project type. " - @"The project can run in '%@' but the embedder is configured as " - @"'%@'", - NSStringFromVMType(_vmTypeRequirement), NSStringFromVMType(embedderVMType)]; - result(NO, message); - return; - } - - switch (_vmTypeRequirement) { - case VMTypeInterpreter: - [self runFromSourceInEngine:engine withEntrypoint:@"main" result:result]; - return; - case VMTypePrecompilation: - [self runFromPrecompiledSourceInEngine:engine withEntrypoint:@"main" result:result]; - return; - case VMTypeInvalid: - break; - } - - return result(NO, @"Internal error"); -} - -#pragma mark - Running from precompiled application bundles - -- (void)runFromPrecompiledSourceInEngine:(shell::Engine*)engine - withEntrypoint:(NSString*)entrypoint - result:(LaunchResult)result { - if (![_precompiledDartBundle load]) { - NSString* message = [NSString - stringWithFormat:@"Could not load the framework ('%@') containing precompiled code.", - _precompiledDartBundle.bundleIdentifier]; - result(NO, message); - return; - } - - NSString* path = [FlutterDartProject pathForFlutterAssetsFromBundle:_precompiledDartBundle]; - if (path.length == 0) { - NSString* message = [NSString stringWithFormat: - @"Could not find the 'flutter_assets' dir in " - @"the precompiled Dart bundle with ID '%@'", - _precompiledDartBundle.bundleIdentifier]; - result(NO, message); - return; - } - - std::string bundle_path = path.UTF8String; - blink::Threads::UI()->PostTask([ - engine = engine->GetWeakPtr(), bundle_path, entrypoint = std::string([entrypoint UTF8String]) - ] { - if (engine) - engine->RunBundle(bundle_path, entrypoint); - }); - - result(YES, @"Success"); -} - -#pragma mark - Running from source - -- (void)runFromSourceInEngine:(shell::Engine*)engine - withEntrypoint:(NSString*)entrypoint - result:(LaunchResult)result { - if (_dartSource == nil) { - result(NO, @"Dart source not specified."); - return; - } - - [_dartSource validate:^(BOOL success, NSString* message) { - if (!success) { - return result(NO, message); - } - - std::string bundle_path = _dartSource.flutterAssets.absoluteURL.path.UTF8String; - - if (_dartSource.assetsDirContainsScriptSnapshot) { - blink::Threads::UI()->PostTask([ - engine = engine->GetWeakPtr(), bundle_path, - entrypoint = std::string([entrypoint UTF8String]) - ] { - if (engine) - engine->RunBundle(bundle_path, entrypoint); - }); - } else { - std::string main = _dartSource.dartMain.absoluteURL.path.UTF8String; - std::string packages = _dartSource.packages.absoluteURL.path.UTF8String; - blink::Threads::UI()->PostTask( - [ engine = engine->GetWeakPtr(), bundle_path, main, packages ] { - if (engine) - engine->RunBundleAndSource(bundle_path, main, packages); - }); - } - - result(YES, @"Success"); - }]; -} - -#pragma mark - Misc. - -- (void)dealloc { - [_precompiledDartBundle unload]; - [_precompiledDartBundle release]; - [_dartSource release]; - - [super dealloc]; -} - @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h index 75db7c4049dd9..7fe1fc364f328 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h @@ -5,32 +5,15 @@ #ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTPROJECT_INTERNAL_H_ #define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTPROJECT_INTERNAL_H_ +#include "flutter/common/settings.h" #include "flutter/shell/common/engine.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterDartProject.h" -enum VMType { - // An invalid VM configuration. - VMTypeInvalid = 0, - // VM can execute Dart code as an interpreter. - VMTypeInterpreter, - // VM can execute precompiled Dart code. - VMTypePrecompilation, -}; - -typedef void (^LaunchResult)(BOOL success, NSString* message); - @interface FlutterDartProject () -- (void)launchInEngine:(shell::Engine*)engine - embedderVMType:(VMType)type - result:(LaunchResult)result; - -- (void)launchInEngine:(shell::Engine*)engine - withEntrypoint:(NSString*)entrypoint - embedderVMType:(VMType)type - result:(LaunchResult)result; +- (const blink::Settings&)settings; -+ (NSString*)pathForFlutterAssetsFromBundle:(NSBundle*)bundle; +- (shell::RunConfiguration)runConfiguration; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h b/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h deleted file mode 100644 index c3881ce065185..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2016 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 SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTSOURCE_H_ -#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTSOURCE_H_ - -#import - -typedef void (^ValidationResult)(BOOL result, NSString* message); - -@interface FlutterDartSource : NSObject - -@property(nonatomic, readonly) NSURL* dartMain; -@property(nonatomic, readonly) NSURL* packages; -@property(nonatomic, readonly) NSURL* flutterAssets; -@property(nonatomic, readonly) BOOL assetsDirContainsScriptSnapshot; - -- (instancetype)initWithDartMain:(NSURL*)dartMain - packages:(NSURL*)packages - flutterAssets:(NSURL*)flutterAssets NS_DESIGNATED_INITIALIZER; - -- (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssets - NS_DESIGNATED_INITIALIZER; - -- (void)validate:(ValidationResult)result; - -@end - -#endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTSOURCE_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm b/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm deleted file mode 100644 index aecb4e5806b3a..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h" - -@implementation FlutterDartSource - -@synthesize dartMain = _dartMain; -@synthesize packages = _packages; -@synthesize flutterAssets = _flutterAssets; -@synthesize assetsDirContainsScriptSnapshot = _assetsDirContainsScriptSnapshot; - -#pragma mark - Convenience Initializers - -- (instancetype)init { - return [self initWithDartMain:nil packages:nil flutterAssets:nil]; -} - -#pragma mark - Designated Initializers - -- (instancetype)initWithDartMain:(NSURL*)dartMain - packages:(NSURL*)packages - flutterAssets:(NSURL*)flutterAssets { - self = [super init]; - - if (self) { - _dartMain = [dartMain copy]; - _packages = [packages copy]; - _flutterAssets = [flutterAssets copy]; - - NSFileManager* fileManager = [NSFileManager defaultManager]; - - const BOOL dartMainExists = [fileManager fileExistsAtPath:dartMain.absoluteURL.path]; - const BOOL packagesExists = [fileManager fileExistsAtPath:packages.absoluteURL.path]; - - if (!dartMainExists || !packagesExists) { - // We cannot actually verify this without opening up the directory. This is - // just an assumption. - _assetsDirContainsScriptSnapshot = YES; - } - } - - return self; -} - -- (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssets { - self = [super init]; - - if (self) { - _flutterAssets = [flutterAssets copy]; - _assetsDirContainsScriptSnapshot = YES; - } - - return self; -} - -static BOOL CheckDartProjectURL(NSMutableString* log, NSURL* url, NSString* logLabel) { - if (url == nil) { - [log appendFormat:@"The %@ was not specified.\n", logLabel]; - return false; - } - - if (!url.isFileURL) { - [log appendFormat:@"The %@ must be a file URL.\n", logLabel]; - return false; - } - - if (![[NSFileManager defaultManager] fileExistsAtPath:url.absoluteURL.path]) { - [log appendFormat:@"No file found at '%@' when looking for the %@.\n", url, logLabel]; - return false; - } - - return true; -} - -- (void)validate:(ValidationResult)result { - NSMutableString* log = [[[NSMutableString alloc] init] autorelease]; - - BOOL isValid = YES; - - isValid &= CheckDartProjectURL(log, _flutterAssets, @"Flutter assets"); - - if (!_assetsDirContainsScriptSnapshot) { - isValid &= CheckDartProjectURL(log, _dartMain, @"Dart main"); - isValid &= CheckDartProjectURL(log, _packages, @"Dart packages"); - } - - result(isValid, log); -} - -- (void)dealloc { - [_dartMain release]; - [_packages release]; - [_flutterAssets release]; - - [super dealloc]; -} - -@end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm index 2143f362f7905..dee11d08934a5 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm @@ -2,38 +2,84 @@ // 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 + #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterHeadlessDartRunner.h" +#include #include -#include "flutter/fml/platform/darwin/scoped_nsobject.h" -#include "flutter/shell/common/null_platform_view.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" +#include "flutter/fml/message_loop.h" +#include "flutter/shell/common/engine.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/run_configuration.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/switches.h" +#include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/darwin/common/command_line.h" +#include "lib/fxl/functional/make_copyable.h" -@interface FlutterHeadlessDartRunner () -@end +static std::unique_ptr CreateHeadlessPlatformView(shell::Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); +} -@implementation FlutterHeadlessDartRunner { - fml::scoped_nsprotocol _dartProject; - std::shared_ptr _platformView; +static std::unique_ptr CreateHeadlessRasterizer(shell::Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); } -- (instancetype)init { - _dartProject.reset([[FlutterDartProject alloc] initFromDefaultSourceForConfiguration]); - _platformView = std::make_shared(); - _platformView->Attach(); - return self; +@implementation FlutterHeadlessDartRunner { + shell::ThreadHost _threadHost; + std::unique_ptr _shell; } - (void)runWithEntrypoint:(NSString*)entrypoint { - const enum VMType type = Dart_IsPrecompiledRuntime() ? VMTypePrecompilation : VMTypeInterpreter; - [_dartProject launchInEngine:&_platformView->engine() - withEntrypoint:entrypoint - embedderVMType:type - result:^(BOOL success, NSString* message) { - if (!success) - NSLog(@"%@", message); - }]; + if (_shell != nullptr || entrypoint.length == 0) { + FXL_LOG(ERROR) << "This headless dart runner was already used to run some code."; + return; + } + + const auto label = "io.flutter.headless"; + + // Create the threads to run the shell on. + _threadHost = { + label, // native thread label + shell::ThreadHost::Type::UI // managed threads to create + }; + + // Configure shell task runners. + auto current_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); + auto single_task_runner = _threadHost.ui_thread->GetTaskRunner(); + blink::TaskRunners task_runners(label, // dart thread label + current_task_runner, // platform + single_task_runner, // gpu + single_task_runner, // ui + single_task_runner // io + ); + + auto settings = shell::SettingsFromCommandLine(shell::CommandLineFromNSProcessInfo()); + + // Create the shell. This is a blocking operation. + _shell = shell::Shell::Create( + std::move(task_runners), // task runners + std::move(settings), // settings + std::bind(&CreateHeadlessPlatformView, std::placeholders::_1), // platform view creation + std::bind(&CreateHeadlessRasterizer, std::placeholders::_1) // rasterzier creation + ); + + if (_shell == nullptr) { + FXL_LOG(ERROR) << "Could not start a shell for the headless dart runner with entrypoint: " + << entrypoint.UTF8String; + return; + } + + // Override the default run configuration with the specified entrypoint. + _shell->GetTaskRunners().GetUITaskRunner()->PostTask( + fxl::MakeCopyable([engine = _shell->GetEngine(), + config = shell::RunConfiguration::InferFromSettings(settings)]() mutable { + if (!engine || !engine->Run(std::move(config))) { + FXL_LOG(ERROR) << "Could not launch engine with configuration."; + } + })); } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.h b/shell/platform/darwin/ios/framework/Source/FlutterView.h index 661940620c947..5e3d303401725 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.h @@ -7,8 +7,14 @@ #include +#include + +#include "flutter/shell/platform/darwin/ios/ios_surface.h" + @interface FlutterView : UIView +- (std::unique_ptr)createSurface; + @end #endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_VIEW_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/shell/platform/darwin/ios/framework/Source/FlutterView.mm index 7c382838c6f5c..27e3d48c4cb50 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -5,20 +5,41 @@ #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/common/settings.h" -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/flow/layers/layer_tree.h" +#include "flutter/fml/trace_event.h" #include "flutter/shell/common/platform_view.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/shell.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" +#include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" +#include "flutter/shell/platform/darwin/ios/ios_surface_software.h" #include "lib/fxl/synchronization/waitable_event.h" #include "third_party/skia/include/utils/mac/SkCGUtils.h" -@interface FlutterView () +@interface FlutterView () @end @implementation FlutterView +- (FlutterViewController*)flutterViewController { + // Find the first view controller in the responder chain and see if it is a FlutterViewController. + for (UIResponder* responder = self.nextResponder; responder != nil; + responder = responder.nextResponder) { + if ([responder isKindOfClass:[UIViewController class]]) { + if ([responder isKindOfClass:[FlutterViewController class]]) { + return reinterpret_cast(responder); + } else { + // Should only happen if a non-FlutterViewController tries to somehow (via dynamic class + // resolution or reparenting) set a FlutterView as its view. + return nil; + } + } + } + return nil; +} + - (void)layoutSubviews { if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { CAEAGLLayer* layer = reinterpret_cast(self.layer); @@ -40,13 +61,24 @@ + (Class)layerClass { #endif // TARGET_IPHONE_SIMULATOR } +- (std::unique_ptr)createSurface { + if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { + fml::scoped_nsobject eagl_layer( + reinterpret_cast([self.layer retain])); + return std::make_unique(std::move(eagl_layer)); + } else { + fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); + return std::make_unique(std::move(layer)); + } +} + - (BOOL)enableInputClicksWhenVisible { return YES; } -void SnapshotRasterizer(fml::WeakPtr rasterizer, - CGContextRef context, - bool is_opaque) { +static void SnapshotRasterizer(fml::WeakPtr rasterizer, + CGContextRef context, + bool is_opaque) { if (!rasterizer) { return; } @@ -77,10 +109,11 @@ void SnapshotRasterizer(fml::WeakPtr rasterizer, SkCanvas canvas(bitmap); - { - flow::CompositorContext compositor_context(nullptr); - auto frame = compositor_context.AcquireFrame(nullptr, &canvas, false /* instrumentation */); - layer_tree->Raster(frame, false /* ignore raster cache. */); + flow::CompositorContext compositor_context; + + if (auto frame = compositor_context.AcquireFrame(nullptr, &canvas, false /* instrumentation */)) { + layer_tree->Preroll(*frame, true /* ignore raster cache */); + layer_tree->Paint(*frame); } canvas.flush(); @@ -89,41 +122,6 @@ void SnapshotRasterizer(fml::WeakPtr rasterizer, SkCGDrawBitmap(context, bitmap, 0, 0); } -static fml::WeakPtr GetRandomRasterizer() { - fml::WeakPtr rasterizer; - shell::Shell::Shared().IteratePlatformViews([&rasterizer](shell::PlatformView* view) -> bool { - rasterizer = view->rasterizer().GetWeakRasterizerPtr(); - // We just grab the first rasterizer so there is no need to iterate - // further. - return false; - }); - return rasterizer; -} - -void SnapshotContents(CGContextRef context, bool is_opaque) { - // TODO(chinmaygarde): Currently, there is no way to get the rasterizer for - // a particular platform view from the shell. But, for now, we only have one - // platform view. So use that. Once we support multiple platform views, the - // shell will need to provide a way to get the rasterizer for a specific - // platform view. - SnapshotRasterizer(GetRandomRasterizer(), context, is_opaque); -} - -void SnapshotContentsSync(CGContextRef context, UIView* view) { - auto gpu_thread = blink::Threads::Gpu(); - - if (!gpu_thread) { - return; - } - - fxl::AutoResetWaitableEvent latch; - gpu_thread->PostTask([&latch, context, view]() { - SnapshotContents(context, [view isOpaque]); - latch.Signal(); - }); - latch.Wait(); -} - // Override the default CALayerDelegate method so that APIs that attempt to // screenshot the view display contents correctly. We cannot depend on // reading @@ -132,7 +130,22 @@ void SnapshotContentsSync(CGContextRef context, UIView* view) { // 2: The call is made of the platform thread and not the GPU thread. // 3: There may be a software rasterizer. - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context { - SnapshotContentsSync(context, self); + TRACE_EVENT0("flutter", "SnapshotFlutterView"); + FlutterViewController* controller = [self flutterViewController]; + + if (controller == nil) { + return; + } + + auto& shell = [controller shell]; + + fxl::AutoResetWaitableEvent latch; + shell.GetTaskRunners().GetGPUTaskRunner()->PostTask( + [&latch, rasterizer = shell.GetRasterizer(), context, opaque = layer.opaque]() { + SnapshotRasterizer(std::move(rasterizer), context, opaque); + latch.Signal(); + }); + latch.Wait(); } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index a467a5a8cf1a5..17e9a4eff48f6 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -2,90 +2,54 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#define FML_USED_ON_EMBEDDER + +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" #include -#include "flutter/common/threads.h" -#include "flutter/flow/texture.h" +#include "flutter/fml/message_loop.h" #include "flutter/fml/platform/darwin/platform_version.h" -#include "flutter/fml/platform/darwin/scoped_block.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" -#include "flutter/lib/ui/painting/resource_context.h" -#include "flutter/shell/platform/darwin/common/buffer_conversions.h" -#include "flutter/shell/platform/darwin/common/platform_mac.h" -#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterCodecs.h" +#include "flutter/shell/common/thread_host.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/shell/platform/darwin/ios/framework/Source/flutter_touch_mapper.h" -#include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h" #include "flutter/shell/platform/darwin/ios/platform_view_ios.h" -#include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/time/time_delta.h" - -namespace { - -typedef void (^PlatformMessageResponseCallback)(NSData*); - -class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { - FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseDarwin); - - public: - void Complete(std::vector data) override { - fxl::RefPtr self(this); - blink::Threads::Platform()->PostTask( - fxl::MakeCopyable([ self, data = std::move(data) ]() mutable { - self->callback_.get()(shell::GetNSDataFromVector(data)); - })); - } - - void CompleteEmpty() override { - fxl::RefPtr self(this); - blink::Threads::Platform()->PostTask( - fxl::MakeCopyable([self]() mutable { self->callback_.get()(nil); })); - } - - private: - explicit PlatformMessageResponseDarwin(PlatformMessageResponseCallback callback) - : callback_(callback, fml::OwnershipPolicy::Retain) {} - fml::ScopedBlock callback_; -}; - -} // namespace - -@interface FlutterViewController () +@interface FlutterViewController () @end @implementation FlutterViewController { - fml::scoped_nsprotocol _dartProject; + fml::scoped_nsobject _dartProject; + shell::ThreadHost _threadHost; + std::unique_ptr _shell; + + // Channels + fml::scoped_nsobject _platformPlugin; + fml::scoped_nsobject _textInputPlugin; + fml::scoped_nsobject _localizationChannel; + fml::scoped_nsobject _navigationChannel; + fml::scoped_nsobject _platformChannel; + fml::scoped_nsobject _textInputChannel; + fml::scoped_nsobject _lifecycleChannel; + fml::scoped_nsobject _systemChannel; + fml::scoped_nsobject _settingsChannel; + + // We keep a separate reference to this and create it ahead of time because we want to be able to + // setup a shell along with its platform view before the view has to appear. + fml::scoped_nsobject _flutterView; + fml::scoped_nsobject _launchView; UIInterfaceOrientationMask _orientationPreferences; UIStatusBarStyle _statusBarStyle; blink::ViewportMetrics _viewportMetrics; shell::TouchMapper _touchMapper; - std::shared_ptr _platformView; - fml::scoped_nsprotocol _platformPlugin; - fml::scoped_nsprotocol _textInputPlugin; - fml::scoped_nsprotocol _localizationChannel; - fml::scoped_nsprotocol _navigationChannel; - fml::scoped_nsprotocol _platformChannel; - fml::scoped_nsprotocol _textInputChannel; - fml::scoped_nsprotocol _lifecycleChannel; - fml::scoped_nsprotocol _systemChannel; - fml::scoped_nsprotocol _settingsChannel; - fml::scoped_nsprotocol _launchView; int64_t _nextTextureId; BOOL _initialized; - BOOL _connected; -} - -+ (void)initialize { - if (self == [FlutterViewController class]) { - shell::FlutterMain(); - } } #pragma mark - Manage and override all designated initializers @@ -125,26 +89,92 @@ - (void)performCommonViewControllerInitialization { _orientationPreferences = UIInterfaceOrientationMaskAll; _statusBarStyle = UIStatusBarStyleDefault; - _platformView = std::make_shared( - reinterpret_cast(self.view.layer), self); - - _platformView->Attach( - // First frame callback. - [self]() { - TRACE_EVENT0("flutter", "First Frame"); - if (_launchView) { - [UIView animateWithDuration:0.2 - animations:^{ - _launchView.get().alpha = 0; - } - completion:^(BOOL finished) { - [_launchView.get() removeFromSuperview]; - _launchView.reset(); - }]; + + if ([self setupShell]) { + [self setupChannels]; + [self setupNotificationCenterObservers]; + } +} + +- (shell::Shell&)shell { + FXL_DCHECK(_shell); + return *_shell; +} + +- (fml::WeakPtr)iosPlatformView { + FXL_DCHECK(_shell); + return _shell->GetPlatformView(); +} + +- (BOOL)setupShell { + FXL_DCHECK(_shell == nullptr); + + static size_t shell_count = 1; + + auto threadLabel = [NSString stringWithFormat:@"io.flutter.%zu", shell_count++]; + + _threadHost = { + threadLabel.UTF8String, // label + shell::ThreadHost::Type::UI | shell::ThreadHost::Type::GPU | shell::ThreadHost::Type::IO}; + + // The current thread will be used as the platform thread. Ensure that the message loop is + // initialized. + fml::MessageLoop::EnsureInitializedForCurrentThread(); + + blink::TaskRunners task_runners(threadLabel.UTF8String, // label + fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform + _threadHost.gpu_thread->GetTaskRunner(), // gpu + _threadHost.ui_thread->GetTaskRunner(), // ui + _threadHost.io_thread->GetTaskRunner() // io + ); + + _flutterView.reset([[FlutterView alloc] init]); + + // Lambda captures by pointers to ObjC objects are fine here because the create call is + // synchronous. + shell::Shell::CreateCallback on_create_platform_view = + [flutter_view_controller = self, flutter_view = _flutterView.get()](shell::Shell& shell) { + auto platform_view_ios = std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + flutter_view_controller, // flutter view controller owner + flutter_view // flutter view owner + ); + return platform_view_ios; + }; + + shell::Shell::CreateCallback on_create_rasterizer = [](shell::Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }; + + // Create the shell. + _shell = shell::Shell::Create(std::move(task_runners), // + [_dartProject settings], // + on_create_platform_view, // + on_create_rasterizer // + ); + + if (!_shell) { + FXL_LOG(ERROR) << "Could not setup a shell to run the Dart application."; + return false; + } + + // Launch the Dart application with the inferred run configuration. + _shell->GetTaskRunners().GetUITaskRunner()->PostTask( + fxl::MakeCopyable([engine = _shell->GetEngine(), // + config = [_dartProject.get() runConfiguration] // + ]() mutable { + if (engine) { + auto result = engine->Run(std::move(config)); + if (!result) { + FXL_LOG(ERROR) << "Could not launch engine with configuration."; + } } - }); - _platformView->SetupResourceContextOnIOThread(); + })); + return true; +} +- (void)setupChannels { _localizationChannel.reset([[FlutterMethodChannel alloc] initWithName:@"flutter/localization" binaryMessenger:self @@ -190,9 +220,8 @@ - (void)performCommonViewControllerInitialization { [_textInputChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { [_textInputPlugin.get() handleMethodCall:call result:result]; }]; - _platformView->SetTextInputPlugin(_textInputPlugin); - - [self setupNotificationCenterObservers]; + static_cast(_shell->GetPlatformView().get()) + ->SetTextInputPlugin(_textInputPlugin); } - (void)setupNotificationCenterObservers { @@ -261,50 +290,24 @@ - (void)setupNotificationCenterObservers { - (void)setInitialRoute:(NSString*)route { [_navigationChannel.get() invokeMethod:@"setInitialRoute" arguments:route]; } -#pragma mark - Initializing the engine - -- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { - exit(0); -} - -- (void)connectToEngineAndLoad { - if (_connected) - return; - _connected = YES; - - TRACE_EVENT0("flutter", "connectToEngineAndLoad"); - - // We ask the VM to check what it supports. - const enum VMType type = Dart_IsPrecompiledRuntime() ? VMTypePrecompilation : VMTypeInterpreter; - - [_dartProject launchInEngine:&_platformView->engine() - embedderVMType:type - result:^(BOOL success, NSString* message) { - if (!success) { - UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Launch Error" - message:message - delegate:self - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alert show]; - [alert release]; - } - }]; -} #pragma mark - Loading the view - (void)loadView { - FlutterView* view = [[FlutterView alloc] init]; - - self.view = view; + self.view = _flutterView.get(); self.view.multipleTouchEnabled = YES; self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [view release]; + [self installLaunchViewIfNecessary]; +} + +#pragma mark - Managing launch views +- (void)installLaunchViewIfNecessary { // Show the launch screen view again on top of the FlutterView if available. // This launch screen view will be removed once the first Flutter frame is rendered. + [_launchView.get() removeFromSuperview]; + _launchView.reset(); NSString* launchStoryboardName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UILaunchStoryboardName"]; if (launchStoryboardName && !self.isBeingPresented && !self.isMovingToParentViewController) { @@ -319,16 +322,57 @@ - (void)loadView { } } +- (void)removeLaunchViewIfPresent { + if (!_launchView) { + return; + } + + [UIView animateWithDuration:0.2 + animations:^{ + _launchView.get().alpha = 0; + } + completion:^(BOOL finished) { + [_launchView.get() removeFromSuperview]; + _launchView.reset(); + }]; +} + +- (void)installLaunchViewCallback { + if (!_shell || !_launchView) { + return; + } + auto weak_platform_view = _shell->GetPlatformView(); + if (!weak_platform_view) { + return; + } + __unsafe_unretained auto weak_flutter_view_controller = self; + // This is on the platform thread. + weak_platform_view->SetNextFrameCallback( + [weak_platform_view, weak_flutter_view_controller, + task_runner = _shell->GetTaskRunners().GetPlatformTaskRunner()]() { + // This is on the GPU thread. + task_runner->PostTask([weak_platform_view, weak_flutter_view_controller]() { + // We check if the weak platform view is alive. If it is alive, then the view controller + // also has to be alive since the view controller owns the platform view via the shell + // association. Thus, we are not convinced that the unsafe unretained weak object is in + // fact alive. + if (weak_platform_view) { + [weak_flutter_view_controller removeLaunchViewIfPresent]; + } + }); + }); +} + #pragma mark - Surface creation and teardown updates - (void)surfaceUpdated:(BOOL)appeared { - FXL_CHECK(_platformView != nullptr); - // NotifyCreated/NotifyDestroyed are synchronous and require hops between the UI and GPU thread. if (appeared) { - _platformView->NotifyCreated(); + [self installLaunchViewCallback]; + _shell->GetPlatformView()->NotifyCreated(); + } else { - _platformView->NotifyDestroyed(); + _shell->GetPlatformView()->NotifyDestroyed(); } } @@ -336,7 +380,6 @@ - (void)surfaceUpdated:(BOOL)appeared { - (void)viewWillAppear:(BOOL)animated { TRACE_EVENT0("flutter", "viewWillAppear"); - [self connectToEngineAndLoad]; // Only recreate surface on subsequent appearances when viewport metrics are known. // First time surface creation is done on viewDidLayoutSubviews. if (_viewportMetrics.physical_width) @@ -391,8 +434,6 @@ - (void)applicationWillResignActive:(NSNotification*)notification { - (void)applicationDidEnterBackground:(NSNotification*)notification { TRACE_EVENT0("flutter", "applicationDidEnterBackground"); [self surfaceUpdated:NO]; - // GrContext operations are blocked when the app is in the background. - blink::ResourceContext::Freeze(); [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.paused"]; } @@ -400,7 +441,6 @@ - (void)applicationWillEnterForeground:(NSNotification*)notification { TRACE_EVENT0("flutter", "applicationWillEnterForeground"); if (_viewportMetrics.physical_width) [self surfaceUpdated:YES]; - blink::ResourceContext::Unfreeze(); [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.inactive"]; } @@ -547,10 +587,11 @@ - (void)dispatchTouches:(NSSet*)touches phase:(UITouchPhase)phase { packet->SetPointerData(i++, pointer_data); } - blink::Threads::UI()->PostTask(fxl::MakeCopyable( - [ engine = _platformView->engine().GetWeakPtr(), packet = std::move(packet) ] { - if (engine.get()) + _shell->GetTaskRunners().GetUITaskRunner()->PostTask( + fxl::MakeCopyable([engine = _shell->GetEngine(), packet = std::move(packet)] { + if (engine) { engine->DispatchPointerDataPacket(*packet); + } })); } @@ -573,13 +614,11 @@ - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { #pragma mark - Handle view resizing - (void)updateViewportMetrics { - blink::Threads::UI()->PostTask( - [ weak_platform_view = _platformView->GetWeakPtr(), metrics = _viewportMetrics ] { - if (!weak_platform_view) { - return; + _shell->GetTaskRunners().GetUITaskRunner()->PostTask( + [engine = _shell->GetEngine(), metrics = _viewportMetrics]() { + if (engine) { + engine->SetViewportMetrics(std::move(metrics)); } - weak_platform_view->UpdateSurfaceSize(); - weak_platform_view->engine().SetViewportMetrics(metrics); }); } @@ -709,7 +748,7 @@ - (void)onVoiceOverChanged:(NSNotification*)notification { #else bool enabled = UIAccessibilityIsVoiceOverRunning(); #endif - _platformView->ToggleAccessibility(self.view, enabled); + _shell->GetPlatformView()->SetSemanticsEnabled(enabled); } #pragma mark - Memory Notifications @@ -875,46 +914,50 @@ - (void)sendOnChannel:(NSString*)channel message:(NSData*)message binaryReply:(FlutterBinaryReply)callback { NSAssert(channel, @"The channel must not be null"); - fxl::RefPtr response = + fxl::RefPtr response = (callback == nil) ? nullptr - : fxl::MakeRefCounted(^(NSData* reply) { - callback(reply); - }); + : fxl::MakeRefCounted( + ^(NSData* reply) { + callback(reply); + }, + _shell->GetTaskRunners().GetPlatformTaskRunner()); fxl::RefPtr platformMessage = (message == nil) ? fxl::MakeRefCounted(channel.UTF8String, response) : fxl::MakeRefCounted( channel.UTF8String, shell::GetVectorFromNSData(message), response); - _platformView->DispatchPlatformMessage(platformMessage); + + _shell->GetPlatformView()->DispatchPlatformMessage(platformMessage); } - (void)setMessageHandlerOnChannel:(NSString*)channel binaryMessageHandler:(FlutterBinaryMessageHandler)handler { NSAssert(channel, @"The channel must not be null"); - _platformView->platform_message_router().SetMessageHandler(channel.UTF8String, handler); + [self iosPlatformView] -> GetPlatformMessageRouter().SetMessageHandler(channel.UTF8String, + handler); } #pragma mark - FlutterTextureRegistry - (int64_t)registerTexture:(NSObject*)texture { int64_t textureId = _nextTextureId++; - _platformView->RegisterExternalTexture(textureId, texture); + [self iosPlatformView] -> RegisterExternalTexture(textureId, texture); return textureId; } - (void)unregisterTexture:(int64_t)textureId { - _platformView->UnregisterTexture(textureId); + _shell->GetPlatformView()->UnregisterTexture(textureId); } - (void)textureFrameAvailable:(int64_t)textureId { - _platformView->MarkTextureFrameAvailable(textureId); + _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId); } - (NSString*)lookupKeyForAsset:(NSString*)asset { - return [FlutterDartProject lookupKeyForAsset:asset]; + return [FlutterDartProject lookupKeyForAsset:asset]; } - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package { - return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package]; + return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package]; } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h new file mode 100644 index 0000000000000..482379c8f17eb --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h @@ -0,0 +1,17 @@ +// 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_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ + +#include "flutter/shell/common/shell.h" +#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" + +@interface FlutterViewController () + +- (shell::Shell&)shell; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index 3f96f37a9c2db..6a545b95e4276 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -427,7 +427,7 @@ - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction { weak_factory_(this) { accessibility_channel_.reset([[FlutterBasicMessageChannel alloc] initWithName:@"flutter/accessibility" - binaryMessenger:platform_view->binary_messenger() + binaryMessenger:platform_view->GetOwnerViewController() codec:[FlutterStandardMessageCodec sharedInstance]]); [accessibility_channel_.get() setMessageHandler:^(id message, FlutterReply reply) { HandleEvent((NSDictionary*)message); @@ -440,7 +440,7 @@ - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction { } UIView* AccessibilityBridge::textInputView() { - return [platform_view_->text_input_plugin() textInputView]; + return [platform_view_->GetTextInputPlugin() textInputView]; } void AccessibilityBridge::UpdateSemantics(blink::SemanticsNodeUpdates nodes) { diff --git a/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h b/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h deleted file mode 100644 index f2e54dd2c2806..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h +++ /dev/null @@ -1,18 +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_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTER_MAIN_IOS_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTER_MAIN_IOS_H_ - -#include "lib/fxl/macros.h" - -namespace shell { - -/// Initializes the Flutter shell. This must be called before interacting with -/// the engine in any way. It is safe to call this method multiple times. -void FlutterMain(); - -} // namespace shell - -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTER_MAIN_IOS_H_ diff --git a/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm b/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm deleted file mode 100644 index aa7ad5fd85727..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm +++ /dev/null @@ -1,25 +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. - -#include "flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h" - -#include "flutter/shell/platform/darwin/common/platform_mac.h" -#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" - -namespace shell { - -void FlutterMain() { - NSBundle* bundle = [NSBundle bundleForClass:[FlutterViewController class]]; - NSString* icuDataPath = [bundle pathForResource:@"icudtl" ofType:@"dat"]; - NSString* libraryName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTLibraryPath"]; - - NSBundle* mainBundle = [NSBundle mainBundle]; - NSString* flutterAssetsPath = [FlutterDartProject pathForFlutterAssetsFromBundle:mainBundle]; - - shell::PlatformMacMain(icuDataPath.UTF8String, libraryName != nil ? libraryName.UTF8String : "", - flutterAssetsPath.UTF8String); -} - -} // namespace shell diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h new file mode 100644 index 0000000000000..b861c5036e97d --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h @@ -0,0 +1,50 @@ +// 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_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_MESSAGE_RESPONSE_DARWIN_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_MESSAGE_RESPONSE_DARWIN_H_ + +#include + +#include "flutter/fml/platform/darwin/scoped_block.h" +#include "flutter/fml/task_runner.h" +#include "flutter/lib/ui/window/platform_message_response.h" +#include "flutter/shell/platform/darwin/common/buffer_conversions.h" +#include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/macros.h" + +typedef void (^PlatformMessageResponseCallback)(NSData*); + +namespace shell { + +class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { + public: + void Complete(std::vector data) override { + fxl::RefPtr self(this); + platform_task_runner_->PostTask(fxl::MakeCopyable([self, data = std::move(data)]() mutable { + self->callback_.get()(shell::GetNSDataFromVector(data)); + })); + } + + void CompleteEmpty() override { + fxl::RefPtr self(this); + platform_task_runner_->PostTask( + fxl::MakeCopyable([self]() mutable { self->callback_.get()(nil); })); + } + + private: + explicit PlatformMessageResponseDarwin(PlatformMessageResponseCallback callback, + fxl::RefPtr platform_task_runner) + : callback_(callback, fml::OwnershipPolicy::Retain), + platform_task_runner_(std::move(platform_task_runner)) {} + + fml::ScopedBlock callback_; + fxl::RefPtr platform_task_runner_; + + FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseDarwin); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_MESSAGE_RESPONSE_DARWIN_H_ diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm new file mode 100644 index 0000000000000..8590b4e36942b --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm @@ -0,0 +1,11 @@ +// 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/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h" + +namespace shell { + +// + +} // namespace shell diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_router.h b/shell/platform/darwin/ios/framework/Source/platform_message_router.h index cfa91c04771c3..d2488f82fe47c 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_message_router.h +++ b/shell/platform/darwin/ios/framework/Source/platform_message_router.h @@ -7,6 +7,7 @@ #include +#include "flutter/fml/platform/darwin/scoped_block.h" #include "flutter/lib/ui/window/platform_message.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterBinaryMessenger.h" #include "lib/fxl/memory/weak_ptr.h" @@ -18,13 +19,13 @@ class PlatformMessageRouter { PlatformMessageRouter(); ~PlatformMessageRouter(); - void HandlePlatformMessage(fxl::RefPtr message); + void HandlePlatformMessage(fxl::RefPtr message) const; void SetMessageHandler(const std::string& channel, FlutterBinaryMessageHandler handler); private: - std::unordered_map + std::unordered_map> message_handlers_; FXL_DISALLOW_COPY_AND_ASSIGN(PlatformMessageRouter); diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_router.mm b/shell/platform/darwin/ios/framework/Source/platform_message_router.mm index 70625143b623e..3ab75bff522f8 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_message_router.mm +++ b/shell/platform/darwin/ios/framework/Source/platform_message_router.mm @@ -14,7 +14,8 @@ PlatformMessageRouter::~PlatformMessageRouter() = default; -void PlatformMessageRouter::HandlePlatformMessage(fxl::RefPtr message) { +void PlatformMessageRouter::HandlePlatformMessage( + fxl::RefPtr message) const { fxl::RefPtr completer = message->response(); auto it = message_handlers_.find(message->channel()); if (it != message_handlers_.end()) { @@ -41,14 +42,10 @@ void PlatformMessageRouter::SetMessageHandler(const std::string& channel, FlutterBinaryMessageHandler handler) { - if (handler) - message_handlers_[channel] = [handler copy]; - else { - auto it = message_handlers_.find(channel); - if (it != message_handlers_.end()) { - [it->second release]; - message_handlers_.erase(it); - } + message_handlers_.erase(channel); + if (handler) { + message_handlers_[channel] = + fml::ScopedBlock{handler, fml::OwnershipPolicy::Retain}; } } diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h index 6a3362b215667..23aaf02510d6d 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h @@ -5,27 +5,26 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_VSYNC_WAITER_IOS_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_VSYNC_WAITER_IOS_H_ +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/vsync_waiter.h" #include "lib/fxl/macros.h" -#if __OBJC__ @class VSyncClient; -#else // __OBJC__ -class VSyncClient; -#endif // __OBJC__ namespace shell { -class VsyncWaiterIOS : public VsyncWaiter { +class VsyncWaiterIOS final : public VsyncWaiter { public: - VsyncWaiterIOS(); - ~VsyncWaiterIOS() override; + VsyncWaiterIOS(blink::TaskRunners task_runners); - void AsyncWaitForVsync(Callback callback) override; + ~VsyncWaiterIOS() override; private: - Callback callback_; - VSyncClient* client_; + fml::scoped_nsobject client_; + + // |shell::VsyncWaiter| + void AwaitVSync() override; FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterIOS); }; diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm index 78d6678189123..4589368acd3fb 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -10,29 +10,62 @@ #include #include -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/glue/trace_event.h" #include "lib/fxl/logging.h" @interface VSyncClient : NSObject +- (instancetype)initWithTaskRunner:(fxl::RefPtr)task_runner + callback:(shell::VsyncWaiter::Callback)callback; + +- (void)await; + +- (void)invalidate; + @end +namespace shell { + +VsyncWaiterIOS::VsyncWaiterIOS(blink::TaskRunners task_runners) + : VsyncWaiter(std::move(task_runners)), + client_([[VSyncClient alloc] initWithTaskRunner:task_runners_.GetUITaskRunner() + callback:std::bind(&VsyncWaiterIOS::FireCallback, + this, + std::placeholders::_1, + std::placeholders::_2)]) {} + +VsyncWaiterIOS::~VsyncWaiterIOS() { + // This way, we will get no more callbacks from the display link that holds a weak (non-nilling) + // reference to this C++ object. + [client_.get() invalidate]; +} + +void VsyncWaiterIOS::AwaitVSync() { + [client_.get() await]; +} + +} // namespace shell + @implementation VSyncClient { - CADisplayLink* _displayLink; - shell::VsyncWaiter::Callback _pendingCallback; + shell::VsyncWaiter::Callback callback_; + fml::scoped_nsobject display_link_; } -- (instancetype)init { +- (instancetype)initWithTaskRunner:(fxl::RefPtr)task_runner + callback:(shell::VsyncWaiter::Callback)callback { self = [super init]; if (self) { - _displayLink = - [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain]; - _displayLink.paused = YES; - - blink::Threads::UI()->PostTask([client = [self retain]]() { - [client->_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + callback_ = std::move(callback); + display_link_ = fml::scoped_nsobject { + [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain] + }; + display_link_.get().paused = YES; + + task_runner->PostTask([client = [self retain]]() { + [client->display_link_.get() addToRunLoop:[NSRunLoop currentRunLoop] + forMode:NSRunLoopCommonModes]; [client release]; }); } @@ -40,68 +73,28 @@ - (instancetype)init { return self; } -- (void)await:(shell::VsyncWaiter::Callback)callback { - FXL_DCHECK(!_pendingCallback); - _pendingCallback = std::move(callback); - _displayLink.paused = NO; +- (void)await { + display_link_.get().paused = NO; } - (void)onDisplayLink:(CADisplayLink*)link { fxl::TimePoint frame_start_time = fxl::TimePoint::Now(); fxl::TimePoint frame_target_time = frame_start_time + fxl::TimeDelta::FromSecondsF(link.duration); - _displayLink.paused = YES; - - // Note: The tag name must be "VSYNC" (it is special) so that the "Highlight - // Vsync" checkbox in the timeline can be enabled. - // See: https://github.com/catapult-project/catapult/blob/2091404475cbba9b786 - // 442979b6ec631305275a6/tracing/tracing/extras/vsync/vsync_auditor.html#L26 -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE - TRACE_EVENT1("flutter", "VSYNC", "mode", "basic"); -#else - { - fxl::TimeDelta delta = frame_target_time.ToEpochDelta(); - constexpr size_t num_chars = sizeof(int64_t) * CHAR_BIT * 3.4 + 2; - char deadline[num_chars]; - sprintf(deadline, "%lld", delta.ToMicroseconds()); - TRACE_EVENT2("flutter", "VSYNC", "mode", "basic", "deadline", deadline); - } -#endif - - // Note: Even though we know we are on the UI thread already (since the - // display link was scheduled on the UI thread in the contructor), we use - // the PostTask mechanism because the callback may have side-effects that need - // to be addressed via a task observer. Invoking the callback by itself - // bypasses such task observers. - // - // We are not using the PostTask for thread switching, but to make task - // observers work. - blink::Threads::UI()->PostTask([ - callback = _pendingCallback, frame_start_time, frame_target_time - ]() { callback(frame_start_time, frame_target_time); }); - - _pendingCallback = nullptr; + display_link_.get().paused = YES; + + callback_(frame_start_time, frame_target_time); +} + +- (void)invalidate { + // [CADisplayLink invalidate] is thread-safe. + [display_link_.get() invalidate]; } - (void)dealloc { - [_displayLink invalidate]; - [_displayLink release]; + [self invalidate]; [super dealloc]; } @end - -namespace shell { - -VsyncWaiterIOS::VsyncWaiterIOS() : client_([[VSyncClient alloc] init]) {} - -VsyncWaiterIOS::~VsyncWaiterIOS() { - [client_ release]; -} - -void VsyncWaiterIOS::AsyncWaitForVsync(Callback callback) { - [client_ await:callback]; -} - -} // namespace shell diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.h b/shell/platform/darwin/ios/ios_external_texture_gl.h index a658fdf31628a..baedf298bd61d 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.h +++ b/shell/platform/darwin/ios/ios_external_texture_gl.h @@ -25,6 +25,8 @@ class IOSExternalTextureGL : public flow::Texture { virtual void OnGrContextDestroyed() override; + virtual void MarkNewFrameAvailable() override; + private: NSObject* external_texture_; fml::CFRef cache_ref_; diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.mm b/shell/platform/darwin/ios/ios_external_texture_gl.mm index 2cc9721e7f09a..0bd9a8ca3c7cb 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.mm +++ b/shell/platform/darwin/ios/ios_external_texture_gl.mm @@ -4,11 +4,10 @@ #include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" -#include +#import #import #import -#include "flutter/common/threads.h" -#include "flutter/lib/ui/painting/resource_context.h" + #include "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" @@ -26,7 +25,6 @@ IOSExternalTextureGL::~IOSExternalTextureGL() = default; void IOSExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds) { - ASSERT_IS_GPU_THREAD; if (!cache_ref_) { CVOpenGLESTextureCacheRef cache; CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, @@ -57,10 +55,8 @@ return; } GrGLTextureInfo textureInfo = {CVOpenGLESTextureGetTarget(texture_ref_), - CVOpenGLESTextureGetName(texture_ref_), - GL_RGBA8_OES}; - GrBackendTexture backendTexture(bounds.width(), bounds.height(), GrMipMapped::kNo, - textureInfo); + CVOpenGLESTextureGetName(texture_ref_), GL_RGBA8_OES}; + GrBackendTexture backendTexture(bounds.width(), bounds.height(), GrMipMapped::kNo, textureInfo); sk_sp image = SkImage::MakeFromTexture(canvas.getGrContext(), backendTexture, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); @@ -69,14 +65,13 @@ GrBackendTexture backendTexture(bounds.width(), bounds.height(), GrMipMapped::kN } } -void IOSExternalTextureGL::OnGrContextCreated() { - ASSERT_IS_GPU_THREAD -} +void IOSExternalTextureGL::OnGrContextCreated() {} void IOSExternalTextureGL::OnGrContextDestroyed() { - ASSERT_IS_GPU_THREAD texture_ref_.Reset(nullptr); cache_ref_.Reset(nullptr); } +void IOSExternalTextureGL::MarkNewFrameAvailable() {} + } // namespace shell diff --git a/shell/platform/darwin/ios/ios_gl_context.h b/shell/platform/darwin/ios/ios_gl_context.h index 89ad7e0347eac..f42c1436461b1 100644 --- a/shell/platform/darwin/ios/ios_gl_context.h +++ b/shell/platform/darwin/ios/ios_gl_context.h @@ -18,7 +18,7 @@ namespace shell { class IOSGLContext { public: - IOSGLContext(PlatformView::SurfaceConfig config, CAEAGLLayer* layer); + IOSGLContext(fml::scoped_nsobject layer); ~IOSGLContext(); diff --git a/shell/platform/darwin/ios/ios_gl_context.mm b/shell/platform/darwin/ios/ios_gl_context.mm index de94018d0689e..77a124e64a291 100644 --- a/shell/platform/darwin/ios/ios_gl_context.mm +++ b/shell/platform/darwin/ios/ios_gl_context.mm @@ -3,21 +3,17 @@ // found in the LICENSE file. #include "flutter/shell/platform/darwin/ios/ios_gl_context.h" -#include "third_party/skia/include/gpu/GrContextOptions.h" -#include "third_party/skia/include/gpu/gl/GrGLInterface.h" #include -namespace shell { +#include "flutter/fml/trace_event.h" +#include "third_party/skia/include/gpu/GrContextOptions.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" -#define VERIFY(x) \ - if (!(x)) { \ - FXL_DLOG(ERROR) << "Failed: " #x; \ - return; \ - }; +namespace shell { -IOSGLContext::IOSGLContext(PlatformView::SurfaceConfig config, CAEAGLLayer* layer) - : layer_([layer retain]), +IOSGLContext::IOSGLContext(fml::scoped_nsobject layer) + : layer_(std::move(layer)), context_([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]), resource_context_([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:context_.get().sharegroup]), @@ -26,34 +22,34 @@ storage_size_width_(0), storage_size_height_(0), valid_(false) { - VERIFY(layer_ != nullptr); - VERIFY(context_ != nullptr); - VERIFY(resource_context_ != nullptr); + FXL_DCHECK(layer_ != nullptr); + FXL_DCHECK(context_ != nullptr); + FXL_DCHECK(resource_context_ != nullptr); bool context_current = [EAGLContext setCurrentContext:context_]; - VERIFY(context_current); - VERIFY(glGetError() == GL_NO_ERROR); + FXL_DCHECK(context_current); + FXL_DCHECK(glGetError() == GL_NO_ERROR); // Generate the framebuffer glGenFramebuffers(1, &framebuffer_); - VERIFY(glGetError() == GL_NO_ERROR); - VERIFY(framebuffer_ != GL_NONE); + FXL_DCHECK(glGetError() == GL_NO_ERROR); + FXL_DCHECK(framebuffer_ != GL_NONE); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_); - VERIFY(glGetError() == GL_NO_ERROR); + FXL_DCHECK(glGetError() == GL_NO_ERROR); // Setup color attachment glGenRenderbuffers(1, &colorbuffer_); - VERIFY(colorbuffer_ != GL_NONE); + FXL_DCHECK(colorbuffer_ != GL_NONE); glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); - VERIFY(glGetError() == GL_NO_ERROR); + FXL_DCHECK(glGetError() == GL_NO_ERROR); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer_); - VERIFY(glGetError() == GL_NO_ERROR); + FXL_DCHECK(glGetError() == GL_NO_ERROR); // TODO: // iOS displays are more variable than just P3 or sRGB. Reading the display @@ -139,24 +135,12 @@ return false; } - GLint width = 0; - GLint height = 0; - - if (colorbuffer_ != GL_NONE) { - // Fetch the dimensions of the color buffer whose backing was just updated - // so that backing of the attachments can be updated - glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width); - FXL_DCHECK(glGetError() == GL_NO_ERROR); - - glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height); - FXL_DCHECK(glGetError() == GL_NO_ERROR); - - glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); - FXL_DCHECK(glGetError() == GL_NO_ERROR); - } + // Fetch the dimensions of the color buffer whose backing was just updated. + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &storage_size_width_); + FXL_DCHECK(glGetError() == GL_NO_ERROR); - storage_size_width_ = width; - storage_size_height_ = height; + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &storage_size_height_); + FXL_DCHECK(glGetError() == GL_NO_ERROR); FXL_DCHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); diff --git a/shell/platform/darwin/ios/ios_surface.h b/shell/platform/darwin/ios/ios_surface.h index c164fab15500e..b629c2709e3d1 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -5,25 +5,17 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_H_ +#include + #include "flutter/fml/platform/darwin/scoped_nsobject.h" -#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/surface.h" #include "lib/fxl/macros.h" -@class CALayer; - namespace shell { class IOSSurface { public: - static std::unique_ptr Create( - PlatformView::SurfaceConfig surface_config, - CALayer* layer); - - IOSSurface(PlatformView::SurfaceConfig surface_config, CALayer* layer); - - CALayer* GetLayer() const; - - PlatformView::SurfaceConfig GetSurfaceConfig() const; + IOSSurface(); virtual ~IOSSurface(); @@ -36,9 +28,6 @@ class IOSSurface { virtual std::unique_ptr CreateGPUSurface() = 0; public: - PlatformView::SurfaceConfig surface_config_; - fml::scoped_nsobject layer_; - FXL_DISALLOW_COPY_AND_ASSIGN(IOSSurface); }; diff --git a/shell/platform/darwin/ios/ios_surface.mm b/shell/platform/darwin/ios/ios_surface.mm index 91067838330f6..b0b9cc3245183 100644 --- a/shell/platform/darwin/ios/ios_surface.mm +++ b/shell/platform/darwin/ios/ios_surface.mm @@ -4,40 +4,15 @@ #include "flutter/shell/platform/darwin/ios/ios_surface.h" -#include -#include #include -@class CALayer; -@class CAEAGLLayer; +#include +#include namespace shell { -std::unique_ptr IOSSurface::Create(PlatformView::SurfaceConfig surface_config, - CALayer* layer) { - // Check if we can use OpenGL. - if ([layer isKindOfClass:[CAEAGLLayer class]]) { - return std::make_unique(surface_config, reinterpret_cast(layer)); - } - - // If we ever support the metal rendering API, a check for CAMetalLayer would - // go here. - - // Finally, fallback to software rendering. - return std::make_unique(surface_config, layer); -} - -IOSSurface::IOSSurface(PlatformView::SurfaceConfig surface_config, CALayer* layer) - : surface_config_(surface_config), layer_([layer retain]) {} +IOSSurface::IOSSurface() = default; IOSSurface::~IOSSurface() = default; -CALayer* IOSSurface::GetLayer() const { - return layer_; -} - -PlatformView::SurfaceConfig IOSSurface::GetSurfaceConfig() const { - return surface_config_; -} - } // namespace shell diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index f7e43e2588984..7486d343eb0fd 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_GL_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_GL_H_ +#include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/gpu/gpu_surface_gl.h" #include "flutter/shell/platform/darwin/ios/ios_gl_context.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" @@ -16,7 +17,7 @@ namespace shell { class IOSSurfaceGL : public IOSSurface, public GPUSurfaceGLDelegate { public: - IOSSurfaceGL(PlatformView::SurfaceConfig surface_config, CAEAGLLayer* layer); + IOSSurfaceGL(fml::scoped_nsobject layer); ~IOSSurfaceGL() override; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index 60756d6094fc9..253531c4800aa 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -4,13 +4,12 @@ #include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" +#include "flutter/fml/trace_event.h" #include "flutter/shell/gpu/gpu_surface_gl.h" namespace shell { -IOSSurfaceGL::IOSSurfaceGL(PlatformView::SurfaceConfig surface_config, CAEAGLLayer* layer) - : IOSSurface(surface_config, reinterpret_cast(layer)), - context_(surface_config, layer) {} +IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer) : context_(std::move(layer)) {} IOSSurfaceGL::~IOSSurfaceGL() = default; diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index 7e3f264b28ce6..e8fc332f06c8c 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -5,17 +5,19 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_SOFTWARE_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_SOFTWARE_H_ +#include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/gpu/gpu_surface_software.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" #include "lib/fxl/macros.h" +@class CALayer; + namespace shell { -class IOSSurfaceSoftware : public IOSSurface, - public GPUSurfaceSoftwareDelegate { +class IOSSurfaceSoftware final : public IOSSurface, + public GPUSurfaceSoftwareDelegate { public: - IOSSurfaceSoftware(PlatformView::SurfaceConfig surface_config, - CALayer* layer); + IOSSurfaceSoftware(fml::scoped_nsobject layer); ~IOSSurfaceSoftware() override; @@ -32,6 +34,7 @@ class IOSSurfaceSoftware : public IOSSurface, bool PresentBackingStore(sk_sp backing_store) override; private: + fml::scoped_nsobject layer_; sk_sp sk_surface_; FXL_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceSoftware); diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index 9a4e90e45dfba..b09a5d9a2d8a3 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -15,15 +15,15 @@ namespace shell { -IOSSurfaceSoftware::IOSSurfaceSoftware(PlatformView::SurfaceConfig surface_config, CALayer* layer) - : IOSSurface(surface_config, layer) { +IOSSurfaceSoftware::IOSSurfaceSoftware(fml::scoped_nsobject layer) + : layer_(std::move(layer)) { UpdateStorageSizeIfNecessary(); } IOSSurfaceSoftware::~IOSSurfaceSoftware() = default; bool IOSSurfaceSoftware::IsValid() const { - return GetLayer() != nullptr; + return layer_; } bool IOSSurfaceSoftware::ResourceContextMakeCurrent() { @@ -120,8 +120,7 @@ return false; } - CALayer* layer = GetLayer(); - layer.contents = reinterpret_cast(static_cast(pixmap_image)); + layer_.get().contents = reinterpret_cast(static_cast(pixmap_image)); return true; } diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index dab19a0f9ce1a..e7849dda44641 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -8,95 +8,66 @@ #include #include "flutter/fml/memory/weak_ptr.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/platform_view.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterTexture.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h" +#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h" #include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" #include "lib/fxl/functional/closure.h" #include "lib/fxl/macros.h" -@class CALayer; -@class UIView; - namespace shell { -class PlatformViewIOS : public PlatformView { +class PlatformViewIOS final : public PlatformView { public: - explicit PlatformViewIOS(CALayer* layer, - NSObject* binaryMessenger); + explicit PlatformViewIOS(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + FlutterViewController* owner_controller_, + FlutterView* owner_view_); ~PlatformViewIOS() override; - void Attach() override; - - void Attach(fxl::Closure firstFrameCallback); - - void NotifyCreated(); - - void ToggleAccessibility(UIView* view, bool enabled); - - PlatformMessageRouter& platform_message_router() { - return platform_message_router_; - } - - fml::WeakPtr GetWeakPtr(); - - void UpdateSurfaceSize(); + PlatformMessageRouter& GetPlatformMessageRouter(); - VsyncWaiter* GetVsyncWaiter() override; - - bool ResourceContextMakeCurrent() override; - - void HandlePlatformMessage( - fxl::RefPtr message) override; + FlutterViewController* GetOwnerViewController() const; void RegisterExternalTexture(int64_t id, NSObject* texture); - void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - - void RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) override; + fml::scoped_nsprotocol GetTextInputPlugin() const; - void SetAssetBundlePath(const std::string& assets_directory) override; - - /** - * Exposes the `FlutterTextInputPlugin` singleton for the - * `AccessibilityBridge` to be able to interact with the text entry system. - */ - fml::scoped_nsprotocol text_input_plugin() { - return text_input_plugin_; - } - - /** - * Sets the `FlutterTextInputPlugin` singleton returned by - * `text_input_plugin`. - */ void SetTextInputPlugin( - fml::scoped_nsprotocol textInputPlugin) { - text_input_plugin_ = textInputPlugin; - } - - NSObject* binary_messenger() const { - return binary_messenger_; - } + fml::scoped_nsprotocol plugin); private: + FlutterViewController* owner_controller_; // weak reference. + FlutterView* owner_view_; // weak reference. std::unique_ptr ios_surface_; PlatformMessageRouter platform_message_router_; std::unique_ptr accessibility_bridge_; - fxl::Closure firstFrameCallback_; - fml::WeakPtrFactory weak_factory_; - NSObject* binary_messenger_; fml::scoped_nsprotocol text_input_plugin_; + fxl::Closure firstFrameCallback_; + + // |shell::PlatformView| + std::unique_ptr CreateRenderingSurface() override; - void SetupAndLoadFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages); + // |shell::PlatformView| + sk_sp CreateResourceContext() const override; + + // |shell::PlatformView| + void SetSemanticsEnabled(bool enabled) override; + + // |shell::PlatformView| + void HandlePlatformMessage( + fxl::RefPtr message) override; + + // |shell::PlatformView| + void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - void SetAssetBundlePathOnUI(const std::string& assets_directory); + // |shell::PlatformView| + std::unique_ptr CreateVSyncWaiter() override; FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewIOS); }; diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index 19c5dd4e663a1..1fba8e5e026e5 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -8,135 +8,92 @@ #include -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/gpu/gpu_rasterizer.h" -#include "flutter/shell/platform/darwin/common/process_info_mac.h" +#include "flutter/shell/common/io_manager.h" #include "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h" #include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" #include "lib/fxl/synchronization/waitable_event.h" namespace shell { -PlatformViewIOS::PlatformViewIOS(CALayer* layer, NSObject* binaryMessenger) - : PlatformView(std::make_unique(std::make_unique())), - ios_surface_(IOSSurface::Create(surface_config_, layer)), - weak_factory_(this), - binary_messenger_(binaryMessenger) {} - -PlatformViewIOS::~PlatformViewIOS() = default; - -void PlatformViewIOS::Attach() { - Attach(NULL); +PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + FlutterViewController* owner_controller, + FlutterView* owner_view) + : PlatformView(delegate, std::move(task_runners)), + owner_controller_(owner_controller), + owner_view_(owner_view), + ios_surface_(owner_view_.createSurface) { + FXL_DCHECK(ios_surface_ != nullptr); + FXL_DCHECK(owner_controller_ != nullptr); + FXL_DCHECK(owner_view_ != nullptr); } -void PlatformViewIOS::Attach(fxl::Closure firstFrameCallback) { - CreateEngine(); - - if (firstFrameCallback) { - firstFrameCallback_ = firstFrameCallback; - rasterizer_->AddNextFrameCallback([weakSelf = GetWeakPtr()] { - if (weakSelf) { - weakSelf->firstFrameCallback_(); - weakSelf->firstFrameCallback_ = nullptr; - } - }); - } -} +PlatformViewIOS::~PlatformViewIOS() = default; -void PlatformViewIOS::NotifyCreated() { - PlatformView::NotifyCreated(ios_surface_->CreateGPUSurface()); +FlutterViewController* PlatformViewIOS::GetOwnerViewController() const { + return owner_controller_; } -void PlatformViewIOS::ToggleAccessibility(UIView* view, bool enabled) { - if (enabled) { - if (!accessibility_bridge_) { - accessibility_bridge_.reset(new shell::AccessibilityBridge(view, this)); - } - } else { - accessibility_bridge_ = nullptr; - } - SetSemanticsEnabled(enabled); +PlatformMessageRouter& PlatformViewIOS::GetPlatformMessageRouter() { + return platform_message_router_; } -void PlatformViewIOS::SetupAndLoadFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) { - blink::Threads::UI()->PostTask( - [ engine = engine().GetWeakPtr(), assets_directory, main, packages ] { - if (engine) - engine->RunBundleAndSource(assets_directory, main, packages); - }); +void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id, + NSObject* texture) { + RegisterTexture(std::make_shared(texture_id, texture)); } -void PlatformViewIOS::SetAssetBundlePathOnUI(const std::string& assets_directory) { - blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), assets_directory ] { - if (engine) - engine->SetAssetBundlePath(assets_directory); - }); +// |shell::PlatformView| +std::unique_ptr PlatformViewIOS::CreateRenderingSurface() { + return ios_surface_->CreateGPUSurface(); } -fml::WeakPtr PlatformViewIOS::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); -} +// |shell::PlatformView| +sk_sp PlatformViewIOS::CreateResourceContext() const { + if (!ios_surface_->ResourceContextMakeCurrent()) { + FXL_DLOG(INFO) << "Could not make resource context current on IO thread. Async texture uploads " + "will be disabled."; + return nullptr; + } -void PlatformViewIOS::UpdateSurfaceSize() { - blink::Threads::Gpu()->PostTask([self = GetWeakPtr()]() { - if (self && self->ios_surface_ != nullptr) { - self->ios_surface_->UpdateStorageSizeIfNecessary(); - } - }); + return IOManager::CreateCompatibleResourceLoadingContext(GrBackend::kOpenGL_GrBackend); } -VsyncWaiter* PlatformViewIOS::GetVsyncWaiter() { - if (!vsync_waiter_) { - vsync_waiter_ = std::make_unique(); +// |shell::PlatformView| +void PlatformViewIOS::SetSemanticsEnabled(bool enabled) { + if (enabled && !accessibility_bridge_) { + accessibility_bridge_ = std::make_unique(owner_view_, this); + } else { + accessibility_bridge_.reset(); } - return vsync_waiter_.get(); -} - -bool PlatformViewIOS::ResourceContextMakeCurrent() { - return ios_surface_ != nullptr ? ios_surface_->ResourceContextMakeCurrent() : false; + PlatformView::SetSemanticsEnabled(enabled); } +// |shell::PlatformView| void PlatformViewIOS::UpdateSemantics(blink::SemanticsNodeUpdates update) { - if (accessibility_bridge_) + if (accessibility_bridge_) { accessibility_bridge_->UpdateSemantics(std::move(update)); + } } +// |shell::PlatformView| void PlatformViewIOS::HandlePlatformMessage(fxl::RefPtr message) { platform_message_router_.HandlePlatformMessage(std::move(message)); } -void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id, - NSObject* texture) { - RegisterTexture(std::make_shared(texture_id, texture)); +// |shell::PlatformView| +std::unique_ptr PlatformViewIOS::CreateVSyncWaiter() { + return std::make_unique(task_runners_); } -void PlatformViewIOS::RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) { - auto latch = new fxl::ManualResetWaitableEvent(); - - dispatch_async(dispatch_get_main_queue(), ^{ - SetupAndLoadFromSource(assets_directory, main, packages); - latch->Signal(); - }); - - latch->Wait(); - delete latch; +fml::scoped_nsprotocol PlatformViewIOS::GetTextInputPlugin() const { + return text_input_plugin_; } -void PlatformViewIOS::SetAssetBundlePath(const std::string& assets_directory) { - auto latch = new fxl::ManualResetWaitableEvent(); - - dispatch_async(dispatch_get_main_queue(), ^{ - SetAssetBundlePathOnUI(assets_directory); - latch->Signal(); - }); - - latch->Wait(); - delete latch; +void PlatformViewIOS::SetTextInputPlugin(fml::scoped_nsprotocol plugin) { + text_input_plugin_ = plugin; } } // namespace shell diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index 7ce6f7e8d5be1..b1e0b3e4f3b71 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -4,16 +4,21 @@ import("$flutter_root/testing/testing.gni") -source_set("embedder") { +static_library("embedder") { + complete_static_lib = true + sources = [ "embedder.cc", "embedder.h", + "embedder_engine.cc", + "embedder_engine.h", "embedder_include.c", "platform_view_embedder.cc", "platform_view_embedder.h", ] deps = [ + "$flutter_root/assets", "$flutter_root/common", "$flutter_root/fml", "$flutter_root/shell/common", @@ -22,6 +27,7 @@ source_set("embedder") { "//third_party/dart/runtime:libdart_jit", "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/skia", + "//third_party/skia:gpu", "//topaz/lib/tonic", ] diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 866413cbc077b..a7ee807934663 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2,14 +2,30 @@ // 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 "lib/fxl/build_config.h" + +#if OS_WIN +#define FLUTTER_EXPORT __declspec(dllexport) +#else // OS_WIN #define FLUTTER_EXPORT __attribute__((visibility("default"))) +#endif // OS_WIN #include "flutter/shell/platform/embedder/embedder.h" #include -#include "flutter/common/threads.h" + +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/common/task_runners.h" +#include "flutter/fml/file.h" #include "flutter/fml/message_loop.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/switches.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/embedder/embedder_engine.h" #include "flutter/shell/platform/embedder/platform_view_embedder.h" +#include "lib/fxl/command_line.h" #include "lib/fxl/functional/make_copyable.h" #define SAFE_ACCESS(pointer, member, default_value) \ @@ -41,21 +57,6 @@ bool IsRendererValid(const FlutterRendererConfig* config) { return true; } -class PlatformViewHolder { - public: - PlatformViewHolder(std::shared_ptr ptr) - : platform_view_(std::move(ptr)) {} - - std::shared_ptr view() const { - return platform_view_; - } - - private: - std::shared_ptr platform_view_; - - FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewHolder); -}; - struct _FlutterPlatformMessageResponseHandle { fxl::RefPtr message; }; @@ -65,6 +66,7 @@ FlutterResult FlutterEngineRun(size_t version, const FlutterProjectArgs* args, void* user_data, FlutterEngine* engine_out) { + // Step 0: Figure out arguments for shell creation. if (version != FLUTTER_ENGINE_VERSION) { return kInvalidLibraryVersion; } @@ -87,51 +89,44 @@ FlutterResult FlutterEngineRun(size_t version, return kInvalidArguments; } - auto make_current = - [ ptr = config->open_gl.make_current, user_data ]()->bool { - return ptr(user_data); - }; + auto make_current = [ptr = config->open_gl.make_current, + user_data]() -> bool { return ptr(user_data); }; - auto clear_current = - [ ptr = config->open_gl.clear_current, user_data ]()->bool { - return ptr(user_data); - }; + auto clear_current = [ptr = config->open_gl.clear_current, + user_data]() -> bool { return ptr(user_data); }; - auto present = [ ptr = config->open_gl.present, user_data ]()->bool { + auto present = [ptr = config->open_gl.present, user_data]() -> bool { return ptr(user_data); }; - auto fbo_callback = - [ ptr = config->open_gl.fbo_callback, user_data ]()->intptr_t { - return ptr(user_data); - }; + auto fbo_callback = [ptr = config->open_gl.fbo_callback, + user_data]() -> intptr_t { return ptr(user_data); }; shell::PlatformViewEmbedder::PlatformMessageResponseCallback platform_message_response_callback = nullptr; if (SAFE_ACCESS(args, platform_message_callback, nullptr) != nullptr) { platform_message_response_callback = - [ ptr = args->platform_message_callback, - user_data ](fxl::RefPtr message) { - auto handle = new FlutterPlatformMessageResponseHandle(); - const FlutterPlatformMessage incoming_message = { - .struct_size = sizeof(FlutterPlatformMessage), - .channel = message->channel().c_str(), - .message = message->data().data(), - .message_size = message->data().size(), - .response_handle = handle, - }; - handle->message = std::move(message); - return ptr(&incoming_message, user_data); - }; + [ptr = args->platform_message_callback, + user_data](fxl::RefPtr message) { + auto handle = new FlutterPlatformMessageResponseHandle(); + const FlutterPlatformMessage incoming_message = { + .struct_size = sizeof(FlutterPlatformMessage), + .channel = message->channel().c_str(), + .message = message->data().data(), + .message_size = message->data().size(), + .response_handle = handle, + }; + handle->message = std::move(message); + return ptr(&incoming_message, user_data); + }; } const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl; std::function make_resource_current_callback = nullptr; if (SAFE_ACCESS(open_gl_config, make_resource_current, nullptr) != nullptr) { - make_resource_current_callback = - [ ptr = config->open_gl.make_resource_current, user_data ]() { - return ptr(user_data); - }; + make_resource_current_callback = [ptr = + config->open_gl.make_resource_current, + user_data]() { return ptr(user_data); }; } std::string icu_data_path; @@ -147,18 +142,33 @@ FlutterResult FlutterEngineRun(size_t version, SAFE_ACCESS(args, command_line_argv, nullptr)); } - static std::once_flag once_shell_initialization; - std::call_once(once_shell_initialization, [&]() { - fxl::CommandLine null_command_line; - shell::Shell::InitStandalone( - std::move(command_line), - icu_data_path, // icu data path default lookup. - "", // application library not supported in JIT mode. - args->assets_path - ); - }); - - shell::PlatformViewEmbedder::DispatchTable table = { + blink::Settings settings = shell::SettingsFromCommandLine(command_line); + settings.icu_data_path = icu_data_path; + settings.main_dart_file_path = args->main_path; + settings.packages_file_path = args->packages_path; + settings.assets_path = args->assets_path; + settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { + fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); + }; + settings.task_observer_remove = [](intptr_t key) { + fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); + }; + + // Create a thread host with the current thread as the platform thread and all + // other threads managed. + shell::ThreadHost thread_host("io.flutter", shell::ThreadHost::Type::GPU | + shell::ThreadHost::Type::IO | + shell::ThreadHost::Type::UI); + fml::MessageLoop::EnsureInitializedForCurrentThread(); + blink::TaskRunners task_runners( + "io.flutter", + fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform + thread_host.gpu_thread->GetTaskRunner(), // gpu + thread_host.ui_thread->GetTaskRunner(), // ui + thread_host.io_thread->GetTaskRunner() // io + ); + + shell::PlatformViewEmbedder::DispatchTable dispatch_table = { .gl_make_current_callback = make_current, .gl_clear_current_callback = clear_current, .gl_present_callback = present, @@ -167,31 +177,55 @@ FlutterResult FlutterEngineRun(size_t version, .gl_make_resource_current_callback = make_resource_current_callback, }; - auto platform_view = std::make_shared(table); - platform_view->Attach(); - - std::string assets(args->assets_path); - std::string main(args->main_path); - std::string packages(args->packages_path); - - blink::Threads::UI()->PostTask([ - weak_engine = platform_view->engine().GetWeakPtr(), // - assets = std::move(assets), // - main = std::move(main), // - packages = std::move(packages) // - ] { - if (auto engine = weak_engine) { - if (main.empty()) { - engine->RunBundle(assets); - } else { - engine->RunBundleAndSource(assets, main, packages); - } - } - }); - - *engine_out = reinterpret_cast( - new PlatformViewHolder(std::move(platform_view))); + shell::Shell::CreateCallback on_create_platform_view = + [dispatch_table](shell::Shell& shell) { + return std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + dispatch_table // embedder dispatch table + ); + }; + + shell::Shell::CreateCallback on_create_rasterizer = + [](shell::Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }; + + // Step 1: Create the engine. + auto embedder_engine = + std::make_unique(std::move(thread_host), // + std::move(task_runners), // + settings, // + on_create_platform_view, // + on_create_rasterizer // + ); + + if (!embedder_engine->IsValid()) { + return kInvalidArguments; + } + + // Step 2: Setup the rendering surface. + if (!embedder_engine->NotifyCreated()) { + return kInvalidArguments; + } + + // Step 3: Run the engine. + auto run_configuration = shell::RunConfiguration::InferFromSettings(settings); + + run_configuration.AddAssetResolver( + std::make_unique( + fml::Duplicate(settings.assets_dir))); + run_configuration.AddAssetResolver( + std::make_unique(fml::OpenFile( + settings.assets_path.c_str(), fml::OpenPermission::kRead, true))); + + if (!embedder_engine->Run(std::move(run_configuration))) { + return kInvalidArguments; + } + + // Finally! Release the ownership of the embedder engine to the caller. + *engine_out = reinterpret_cast(embedder_engine.release()); return kSuccess; } @@ -199,7 +233,9 @@ FlutterResult FlutterEngineShutdown(FlutterEngine engine) { if (engine == nullptr) { return kInvalidArguments; } - delete reinterpret_cast(engine); + auto embedder_engine = reinterpret_cast(engine); + embedder_engine->NotifyDestroyed(); + delete embedder_engine; return kSuccess; } @@ -210,21 +246,16 @@ FlutterResult FlutterEngineSendWindowMetricsEvent( return kInvalidArguments; } - auto holder = reinterpret_cast(engine); - blink::ViewportMetrics metrics; metrics.physical_width = SAFE_ACCESS(flutter_metrics, width, 0.0); metrics.physical_height = SAFE_ACCESS(flutter_metrics, height, 0.0); metrics.device_pixel_ratio = SAFE_ACCESS(flutter_metrics, pixel_ratio, 1.0); - blink::Threads::UI()->PostTask( - [ weak_engine = holder->view()->engine().GetWeakPtr(), metrics ] { - if (auto engine = weak_engine) { - engine->SetViewportMetrics(metrics); - } - }); - return kSuccess; + return reinterpret_cast(engine)->SetViewportMetrics( + std::move(metrics)) + ? kSuccess + : kInvalidArguments; } inline blink::PointerData::Change ToPointerDataChange( @@ -267,19 +298,10 @@ FlutterResult FlutterEngineSendPointerEvent(FlutterEngine engine, reinterpret_cast(current) + current->struct_size); } - blink::Threads::UI()->PostTask(fxl::MakeCopyable([ - weak_engine = reinterpret_cast(engine) - ->view() - ->engine() - .GetWeakPtr(), - packet = std::move(packet) - ] { - if (auto engine = weak_engine) { - engine->DispatchPointerDataPacket(*packet); - } - })); - - return kSuccess; + return reinterpret_cast(engine) + ->DispatchPointerDataPacket(std::move(packet)) + ? kSuccess + : kInvalidArguments; } FlutterResult FlutterEngineSendPlatformMessage( @@ -294,8 +316,6 @@ FlutterResult FlutterEngineSendPlatformMessage( return kInvalidArguments; } - auto holder = reinterpret_cast(engine); - auto message = fxl::MakeRefCounted( flutter_message->channel, std::vector( @@ -303,13 +323,10 @@ FlutterResult FlutterEngineSendPlatformMessage( flutter_message->message + flutter_message->message_size), nullptr); - blink::Threads::UI()->PostTask( - [ weak_engine = holder->view()->engine().GetWeakPtr(), message ] { - if (auto engine = weak_engine) { - engine->DispatchPlatformMessage(message); - } - }); - return kSuccess; + return reinterpret_cast(engine)->SendPlatformMessage( + std::move(message)) + ? kSuccess + : kInvalidArguments; } FlutterResult FlutterEngineSendPlatformMessageResponse( diff --git a/shell/platform/embedder/embedder_engine.cc b/shell/platform/embedder/embedder_engine.cc new file mode 100644 index 0000000000000..7416441d7902e --- /dev/null +++ b/shell/platform/embedder/embedder_engine.cc @@ -0,0 +1,119 @@ +// 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/shell/platform/embedder/embedder_engine.h" + +#include "lib/fxl/functional/make_copyable.h" + +#ifdef ERROR +#undef ERROR +#endif + +namespace shell { + +EmbedderEngine::EmbedderEngine( + ThreadHost thread_host, + blink::TaskRunners task_runners, + blink::Settings settings, + Shell::CreateCallback on_create_platform_view, + Shell::CreateCallback on_create_rasterizer) + : thread_host_(std::move(thread_host)), + shell_(Shell::Create(std::move(task_runners), + std::move(settings), + on_create_platform_view, + on_create_rasterizer)) { + is_valid_ = shell_ != nullptr; +} + +EmbedderEngine::~EmbedderEngine() = default; + +bool EmbedderEngine::IsValid() const { + return is_valid_; +} + +bool EmbedderEngine::NotifyCreated() { + if (!IsValid()) { + return false; + } + + shell_->GetPlatformView()->NotifyCreated(); + return true; +} + +bool EmbedderEngine::NotifyDestroyed() { + if (!IsValid()) { + return false; + } + + shell_->GetPlatformView()->NotifyDestroyed(); + return true; +} + +bool EmbedderEngine::Run(RunConfiguration run_configuration) { + if (!IsValid()) { + return false; + } + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask( + fxl::MakeCopyable([engine = shell_->GetEngine(), // engine + config = std::move(run_configuration) // config + ]() mutable { + if (engine) { + auto result = engine->Run(std::move(config)); + if (!result) { + FXL_LOG(ERROR) << "Could not launch the engine with configuration."; + } + } + })); + + return true; +} + +bool EmbedderEngine::SetViewportMetrics(blink::ViewportMetrics metrics) { + if (!IsValid()) { + return false; + } + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask( + [engine = shell_->GetEngine(), metrics = std::move(metrics)]() { + if (engine) { + engine->SetViewportMetrics(std::move(metrics)); + } + }); + return true; +} + +bool EmbedderEngine::DispatchPointerDataPacket( + std::unique_ptr packet) { + if (!IsValid() || !packet) { + return false; + } + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask(fxl::MakeCopyable( + [engine = shell_->GetEngine(), packet = std::move(packet)] { + if (engine) { + engine->DispatchPointerDataPacket(*packet); + } + })); + + return true; +} + +bool EmbedderEngine::SendPlatformMessage( + fxl::RefPtr message) { + if (!IsValid() || !message) { + return false; + } + + shell_->GetTaskRunners().GetUITaskRunner()->PostTask( + [engine = shell_->GetEngine(), message] { + if (engine) { + engine->DispatchPlatformMessage(message); + } + }); + + return true; +} + +} // namespace shell diff --git a/shell/platform/embedder/embedder_engine.h b/shell/platform/embedder/embedder_engine.h new file mode 100644 index 0000000000000..c01b86c2aac47 --- /dev/null +++ b/shell/platform/embedder/embedder_engine.h @@ -0,0 +1,53 @@ +// 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_SHELL_PLATFORM_EMBEDDER_EMBEDDER_ENGINE_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_ENGINE_H_ + +#include + +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "lib/fxl/macros.h" + +namespace shell { + +// The object that is returned to the embedder as an opaque pointer to the +// instance of the Flutter engine. +class EmbedderEngine { + public: + EmbedderEngine(ThreadHost thread_host, blink::TaskRunners task_runners, + blink::Settings settings, + Shell::CreateCallback on_create_platform_view, + Shell::CreateCallback on_create_rasterizer); + + ~EmbedderEngine(); + + bool NotifyCreated(); + + bool NotifyDestroyed(); + + bool Run(RunConfiguration run_configuration); + + bool IsValid() const; + + bool SetViewportMetrics(blink::ViewportMetrics metrics); + + bool DispatchPointerDataPacket( + std::unique_ptr packet); + + bool SendPlatformMessage(fxl::RefPtr message); + + private: + const ThreadHost thread_host_; + std::unique_ptr shell_; + bool is_valid_ = false; + + FXL_DISALLOW_COPY_AND_ASSIGN(EmbedderEngine); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_ENGINE_H_ diff --git a/shell/platform/embedder/platform_view_embedder.cc b/shell/platform/embedder/platform_view_embedder.cc index 46e0390770da4..db1bea35c691e 100644 --- a/shell/platform/embedder/platform_view_embedder.cc +++ b/shell/platform/embedder/platform_view_embedder.cc @@ -3,17 +3,18 @@ // found in the LICENSE file. #include "flutter/shell/platform/embedder/platform_view_embedder.h" -#include "flutter/shell/gpu/gpu_rasterizer.h" + +#include "flutter/shell/common/io_manager.h" namespace shell { -PlatformViewEmbedder::PlatformViewEmbedder(DispatchTable dispatch_table) - : PlatformView(std::make_unique(nullptr)), +PlatformViewEmbedder::PlatformViewEmbedder(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + DispatchTable dispatch_table) + : PlatformView(delegate, std::move(task_runners)), dispatch_table_(dispatch_table) {} -PlatformViewEmbedder::~PlatformViewEmbedder() { - NotifyDestroyed(); -} +PlatformViewEmbedder::~PlatformViewEmbedder() = default; bool PlatformViewEmbedder::GLContextMakeCurrent() { return dispatch_table_.gl_make_current_callback(); @@ -31,33 +32,6 @@ intptr_t PlatformViewEmbedder::GLContextFBO() const { return dispatch_table_.gl_fbo_callback(); } -void PlatformViewEmbedder::Attach() { - CreateEngine(); - NotifyCreated(std::make_unique(this)); - - if (dispatch_table_.gl_make_resource_current_callback != nullptr) { - SetupResourceContextOnIOThread(); - } -} - -bool PlatformViewEmbedder::ResourceContextMakeCurrent() { - if (dispatch_table_.gl_make_resource_current_callback == nullptr) { - return false; - } - return dispatch_table_.gl_make_resource_current_callback(); -} - -void PlatformViewEmbedder::RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) { - FXL_LOG(INFO) << "Hot reloading is unsupported on this platform."; -} - -void PlatformViewEmbedder::SetAssetBundlePath( - const std::string& assets_directory) { - FXL_LOG(INFO) << "Set asset bundle path is unsupported on this platform."; -} - void PlatformViewEmbedder::HandlePlatformMessage( fxl::RefPtr message) { if (!message) { @@ -76,4 +50,17 @@ void PlatformViewEmbedder::HandlePlatformMessage( dispatch_table_.platform_message_response_callback(std::move(message)); } +std::unique_ptr PlatformViewEmbedder::CreateRenderingSurface() { + return std::make_unique(this); +} + +sk_sp PlatformViewEmbedder::CreateResourceContext() const { + auto callback = dispatch_table_.gl_make_resource_current_callback; + if (callback && callback()) { + return IOManager::CreateCompatibleResourceLoadingContext( + GrBackend::kOpenGL_GrBackend); + } + return nullptr; +} + } // namespace shell diff --git a/shell/platform/embedder/platform_view_embedder.h b/shell/platform/embedder/platform_view_embedder.h index c287fc5ac86f1..a5b76dfaa07ba 100644 --- a/shell/platform/embedder/platform_view_embedder.h +++ b/shell/platform/embedder/platform_view_embedder.h @@ -12,7 +12,8 @@ namespace shell { -class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { +class PlatformViewEmbedder final : public PlatformView, + public GPUSurfaceGLDelegate { public: using PlatformMessageResponseCallback = std::function)>; @@ -26,9 +27,11 @@ class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { std::function gl_make_resource_current_callback; // optional }; - PlatformViewEmbedder(DispatchTable dispatch_table); + PlatformViewEmbedder(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + DispatchTable dispatch_table); - ~PlatformViewEmbedder(); + ~PlatformViewEmbedder() override; // |shell::GPUSurfaceGLDelegate| bool GLContextMakeCurrent() override; @@ -42,20 +45,6 @@ class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { // |shell::GPUSurfaceGLDelegate| intptr_t GLContextFBO() const override; - // |shell::PlatformView| - void Attach() override; - - // |shell::PlatformView| - bool ResourceContextMakeCurrent() override; - - // |shell::PlatformView| - void RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) override; - - // |shell::PlatformView| - void SetAssetBundlePath(const std::string& assets_directory) override; - // |shell::PlatformView| void HandlePlatformMessage( fxl::RefPtr message) override; @@ -63,6 +52,12 @@ class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { private: DispatchTable dispatch_table_; + // |shell::PlatformView| + std::unique_ptr CreateRenderingSurface() override; + + // |shell::PlatformView| + sk_sp CreateResourceContext() const override; + FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewEmbedder); }; diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn deleted file mode 100644 index 6e9f1f596b09d..0000000000000 --- a/shell/platform/linux/BUILD.gn +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2016 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. - -executable("linux") { - output_name = "flutter_tester" - - sources = [ - "main_linux.cc", - ] - - deps = [ - "//third_party/dart/runtime:libdart_jit", - "//third_party/dart/runtime/bin:embedded_dart_io", - "$flutter_root/common", - "$flutter_root/fml", - "$flutter_root/shell/common", - "$flutter_root/shell/testing", - "//garnet/public/lib/fxl", - "//third_party/skia", - "//topaz/lib/tonic", - ] -} diff --git a/shell/platform/linux/main_linux.cc b/shell/platform/linux/main_linux.cc deleted file mode 100644 index a20d425ed1eed..0000000000000 --- a/shell/platform/linux/main_linux.cc +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2015 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. - -#include "flutter/common/threads.h" -#include "flutter/fml/message_loop.h" -#include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/shell.h" -#include "flutter/shell/common/switches.h" -#include "flutter/shell/testing/test_runner.h" -#include "flutter/shell/testing/testing.h" -#include "flutter/sky/engine/public/web/Sky.h" -#include "lib/fxl/command_line.h" -#include "lib/tonic/dart_microtask_queue.h" -#include "third_party/dart/runtime/bin/embedded_dart_io.h" - -namespace { - -// Exit codes used by the Dart command line tool. -const int kApiErrorExitCode = 253; -const int kCompilationErrorExitCode = 254; -const int kErrorExitCode = 255; - -// Checks whether the engine's main Dart isolate has no pending work. If so, -// then exit the given message loop. -class ScriptCompletionTaskObserver : public fml::TaskObserver { - public: - ScriptCompletionTaskObserver(fxl::RefPtr task_runner) - : main_task_runner_(std::move(task_runner)), - prev_live_(false), - last_error_(tonic::kNoError) {} - - void DidProcessTask() override { - shell::TestRunner& test_runner = shell::TestRunner::Shared(); - shell::Engine& engine = test_runner.platform_view().engine(); - - if (engine.GetLoadScriptError() != tonic::kNoError) { - last_error_ = engine.GetLoadScriptError(); - main_task_runner_->PostTask( - []() { fml::MessageLoop::GetCurrent().Terminate(); }); - return; - } - - bool live = engine.UIIsolateHasLivePorts(); - if (prev_live_ && !live) { - last_error_ = engine.GetUIIsolateLastError(); - main_task_runner_->PostTask( - []() { fml::MessageLoop::GetCurrent().Terminate(); }); - } - prev_live_ = live; - } - - tonic::DartErrorHandleType last_error() { return last_error_; } - - private: - fxl::RefPtr main_task_runner_; - bool prev_live_; - tonic::DartErrorHandleType last_error_; -}; - -int ConvertErrorTypeToExitCode(tonic::DartErrorHandleType error) { - switch (error) { - case tonic::kCompilationErrorType: - return kCompilationErrorExitCode; - case tonic::kApiErrorType: - return kApiErrorExitCode; - case tonic::kUnknownErrorType: - return kErrorExitCode; - default: - return 0; - } -} - -void RunNonInteractive(fxl::CommandLine initial_command_line, - bool run_forever) { - // This is a platform thread (i.e not one created by fml::Thread), so perform - // one time initialization. - fml::MessageLoop::EnsureInitializedForCurrentThread(); - - std::string bundle_path = ""; - initial_command_line.GetOptionValue( - FlagForSwitch(shell::Switch::FlutterAssetsDir), &bundle_path); - - shell::Shell::InitStandalone(initial_command_line, - /* icu_data_path= */ "", - /* application_library_path= */ "", bundle_path); - - // Note that this task observer must be added after the observer that drains - // the microtask queue. - ScriptCompletionTaskObserver task_observer( - fml::MessageLoop::GetCurrent().GetTaskRunner()); - if (!run_forever) { - blink::Threads::UI()->PostTask([&task_observer] { - fml::MessageLoop::GetCurrent().AddTaskObserver(&task_observer); - }); - } - - if (!shell::InitForTesting(initial_command_line)) { - shell::PrintUsage("flutter_tester"); - exit(EXIT_FAILURE); - return; - } - - fml::MessageLoop::GetCurrent().Run(); - - shell::TestRunner& test_runner = shell::TestRunner::Shared(); - tonic::DartErrorHandleType error = - test_runner.platform_view().engine().GetLoadScriptError(); - if (error == tonic::kNoError) - error = task_observer.last_error(); - if (error == tonic::kNoError) { - fxl::AutoResetWaitableEvent latch; - blink::Threads::UI()->PostTask([&error, &latch] { - error = tonic::DartMicrotaskQueue::GetForCurrentThread()->GetLastError(); - latch.Signal(); - }); - latch.Wait(); - } - - // The script has completed and the engine may not be in a clean state, - // so just stop the process. - exit(ConvertErrorTypeToExitCode(error)); -} - -} // namespace - -int main(int argc, char* argv[]) { - dart::bin::SetExecutableName(argv[0]); - dart::bin::SetExecutableArguments(argc - 1, argv); - - auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); - - if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { - shell::PrintUsage("flutter_tester"); - return EXIT_SUCCESS; - } - - bool run_forever = - command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever)); - RunNonInteractive(std::move(command_line), run_forever); - return EXIT_SUCCESS; -} diff --git a/shell/platform/win/BUILD.gn b/shell/platform/win/BUILD.gn deleted file mode 100644 index b4a2fe5033c18..0000000000000 --- a/shell/platform/win/BUILD.gn +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2016 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. - -executable("win") { - output_name = "flutter_tester" - - sources = [ - "main_win.cc", - ] - - deps = [ - "//flutter/common", - "//flutter/flow", - "//flutter/fml", - "//flutter/shell/common", - "//flutter/shell/testing", - "//flutter/sky/engine/wtf", - "//garnet/public/lib/fxl", - "//third_party/dart/runtime/bin:embedded_dart_io", - "//third_party/dart/runtime:libdart_jit", - "//third_party/skia", - "//topaz/lib/tonic", - ] - - libs = [ - "iphlpapi.lib", - "Rpcrt4.lib" - ] -} diff --git a/shell/platform/win/main_win.cc b/shell/platform/win/main_win.cc deleted file mode 100644 index c31c88ca915cb..0000000000000 --- a/shell/platform/win/main_win.cc +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2015 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. - -#include - -#include "flutter/common/threads.h" -#include "flutter/fml/message_loop.h" -#include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/shell.h" -#include "flutter/shell/common/switches.h" -#include "flutter/shell/testing/test_runner.h" -#include "flutter/shell/testing/testing.h" -#include "lib/fxl/command_line.h" -#include "lib/tonic/dart_microtask_queue.h" -#include "third_party/dart/runtime/bin/embedded_dart_io.h" - -namespace { - -// Exit codes used by the Dart command line tool. -const int kApiErrorExitCode = 253; -const int kCompilationErrorExitCode = 254; -const int kErrorExitCode = 255; - -// Checks whether the engine's main Dart isolate has no pending work. If so, -// then exit the given message loop. -class ScriptCompletionTaskObserver : public fml::TaskObserver { - public: - ScriptCompletionTaskObserver(fxl::RefPtr task_runner) - : main_task_runner_(std::move(task_runner)), - prev_live_(false), - last_error_(tonic::kNoError) {} - - void DidProcessTask() override { - shell::TestRunner& test_runner = shell::TestRunner::Shared(); - shell::Engine& engine = test_runner.platform_view().engine(); - - if (engine.GetLoadScriptError() != tonic::kNoError) { - last_error_ = engine.GetLoadScriptError(); - main_task_runner_->PostTask( - []() { fml::MessageLoop::GetCurrent().Terminate(); }); - return; - } - - bool live = engine.UIIsolateHasLivePorts(); - if (prev_live_ && !live) { - last_error_ = engine.GetUIIsolateLastError(); - main_task_runner_->PostTask( - []() { fml::MessageLoop::GetCurrent().Terminate(); }); - } - prev_live_ = live; - } - - tonic::DartErrorHandleType last_error() { return last_error_; } - - private: - fxl::RefPtr main_task_runner_; - bool prev_live_; - tonic::DartErrorHandleType last_error_; -}; - -int ConvertErrorTypeToExitCode(tonic::DartErrorHandleType error) { - switch (error) { - case tonic::kCompilationErrorType: - return kCompilationErrorExitCode; - case tonic::kApiErrorType: - return kApiErrorExitCode; - case tonic::kUnknownErrorType: - return kErrorExitCode; - default: - return 0; - } -} - -void RunNonInteractive(fxl::CommandLine initial_command_line, - bool run_forever) { - // This is a platform thread (i.e not one created by fml::Thread), so perform - // one time initialization. - fml::MessageLoop::EnsureInitializedForCurrentThread(); - - std::string bundle_path = ""; - initial_command_line.GetOptionValue( - FlagForSwitch(shell::Switch::FlutterAssetsDir), &bundle_path); - - shell::Shell::InitStandalone(initial_command_line, - /* icu_data_path= */ "", - /* application_library_path= */ "", bundle_path); - - // Note that this task observer must be added after the observer that drains - // the microtask queue. - ScriptCompletionTaskObserver task_observer( - fml::MessageLoop::GetCurrent().GetTaskRunner()); - if (!run_forever) { - blink::Threads::UI()->PostTask([&task_observer] { - fml::MessageLoop::GetCurrent().AddTaskObserver(&task_observer); - }); - } - - if (!shell::InitForTesting(initial_command_line)) { - shell::PrintUsage("flutter_tester"); - ::ExitProcess(EXIT_FAILURE); - return; - } - - fml::MessageLoop::GetCurrent().Run(); - shell::TestRunner& test_runner = shell::TestRunner::Shared(); - tonic::DartErrorHandleType error = - test_runner.platform_view().engine().GetLoadScriptError(); - if (error == tonic::kNoError) - error = task_observer.last_error(); - if (error == tonic::kNoError) { - fxl::AutoResetWaitableEvent latch; - blink::Threads::UI()->PostTask([&error, &latch] { - error = tonic::DartMicrotaskQueue::GetForCurrentThread()->GetLastError(); - latch.Signal(); - }); - latch.Wait(); - } - - // The script has completed and the engine may not be in a clean state, - // so just stop the process. - ::ExitProcess(ConvertErrorTypeToExitCode(error)); -} - -} // namespace - -int main(int argc, char* argv[]) { - dart::bin::SetExecutableName(argv[0]); - dart::bin::SetExecutableArguments(argc - 1, argv); - - auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); - - if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { - shell::PrintUsage("flutter_tester"); - return EXIT_SUCCESS; - } - - bool run_forever = - command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever)); - RunNonInteractive(std::move(command_line), run_forever); - return EXIT_SUCCESS; -} diff --git a/shell/testing/BUILD.gn b/shell/testing/BUILD.gn index 659c241cc49b8..f11a3a2d07501 100644 --- a/shell/testing/BUILD.gn +++ b/shell/testing/BUILD.gn @@ -2,24 +2,30 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -source_set("testing") { +executable("testing") { + testonly = true + + output_name = "flutter_tester" + + public_configs = [ "$flutter_root:config" ] + sources = [ - "platform_view_test.cc", - "platform_view_test.h", - "test_runner.cc", - "test_runner.h", - "testing.cc", - "testing.h", + "tester_main.cc", ] deps = [ + "$flutter_root/assets", "$flutter_root/common", + "$flutter_root/fml", "$flutter_root/shell/common", "//garnet/public/lib/fxl", + "//third_party/dart/runtime:libdart_jit", + "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/skia", + "//topaz/lib/tonic", ] - public_configs = [ - "$flutter_root:config", - ] + if (is_linux) { + ldflags = [ "-rdynamic" ] + } } diff --git a/shell/testing/platform_view_test.cc b/shell/testing/platform_view_test.cc deleted file mode 100644 index a59684d31bc94..0000000000000 --- a/shell/testing/platform_view_test.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 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. - -#include "flutter/shell/testing/platform_view_test.h" - -#include "flutter/shell/common/null_rasterizer.h" -#include "flutter/shell/common/shell.h" - -namespace shell { - -PlatformViewTest::PlatformViewTest() - : PlatformView(std::unique_ptr(new NullRasterizer())) {} - -void PlatformViewTest::Attach() { - CreateEngine(); -} - -PlatformViewTest::~PlatformViewTest() = default; - -bool PlatformViewTest::ResourceContextMakeCurrent() { - return false; -} - -void PlatformViewTest::RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) {} - -void PlatformViewTest::SetAssetBundlePath(const std::string& assets_directory) { -} - -} // namespace shell diff --git a/shell/testing/platform_view_test.h b/shell/testing/platform_view_test.h deleted file mode 100644 index 3612d0363ab58..0000000000000 --- a/shell/testing/platform_view_test.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 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 SHELL_TESTING_PLATFORM_VIEW_TEST_H_ -#define SHELL_TESTING_PLATFORM_VIEW_TEST_H_ - -#include "flutter/shell/common/platform_view.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" - -namespace shell { - -class Shell; - -class PlatformViewTest : public PlatformView { - public: - PlatformViewTest(); - - ~PlatformViewTest(); - - virtual void Attach() override; - - bool ResourceContextMakeCurrent() override; - - void RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) override; - - void SetAssetBundlePath(const std::string& assets_directory) override; - - private: - FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewTest); -}; - -} // namespace shell - -#endif // SHELL_TESTING_PLATFORM_VIEW_TEST_H_ diff --git a/shell/testing/test_runner.cc b/shell/testing/test_runner.cc deleted file mode 100644 index 838b04120c773..0000000000000 --- a/shell/testing/test_runner.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2014 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. - -#include "flutter/shell/testing/test_runner.h" - -#include - -#include "flutter/common/threads.h" -#include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/shell.h" -#include "flutter/shell/testing/platform_view_test.h" - -namespace shell { - -TestRunner::TestRunner() - : platform_view_(std::make_shared()) { - platform_view_->Attach(); - blink::ViewportMetrics metrics; - metrics.device_pixel_ratio = 3.0; - metrics.physical_width = 2400; // 800 at 3x resolution - metrics.physical_height = 1800; // 600 at 3x resolution - - blink::Threads::UI()->PostTask( - [ engine = platform_view_->engine().GetWeakPtr(), metrics ] { - if (engine) - engine->SetViewportMetrics(metrics); - }); -} - -TestRunner::~TestRunner() = default; - -TestRunner& TestRunner::Shared() { - static TestRunner* g_test_runner = nullptr; - if (!g_test_runner) - g_test_runner = new TestRunner(); - return *g_test_runner; -} - -void TestRunner::Run(const TestDescriptor& test) { - blink::Threads::UI()->PostTask( - [ engine = platform_view_->engine().GetWeakPtr(), test ] { - if (engine) - engine->RunBundleAndSource(std::string(), test.path, test.packages); - }); -} - -} // namespace shell diff --git a/shell/testing/test_runner.h b/shell/testing/test_runner.h deleted file mode 100644 index 8f303d7eb7683..0000000000000 --- a/shell/testing/test_runner.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015 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 SHELL_TESTING_TEST_RUNNER_H_ -#define SHELL_TESTING_TEST_RUNNER_H_ - -#include -#include - -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" - -namespace shell { - -class PlatformView; - -class TestRunner { - public: - static TestRunner& Shared(); - - struct TestDescriptor { - std::string path; - std::string packages; - }; - - void Run(const TestDescriptor& test); - - PlatformView& platform_view() { return *platform_view_; } - - private: - TestRunner(); - ~TestRunner(); - - std::shared_ptr platform_view_; - - FXL_DISALLOW_COPY_AND_ASSIGN(TestRunner); -}; - -} // namespace shell - -#endif // SHELL_TESTING_TEST_RUNNER_H_ diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc new file mode 100644 index 0000000000000..a9e7bafc74d93 --- /dev/null +++ b/shell/testing/tester_main.cc @@ -0,0 +1,243 @@ +// 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. + +#define FML_USED_ON_EMBEDDER + +#include + +#include "flutter/assets/asset_manager.h" +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/fml/file.h" +#include "flutter/fml/message_loop.h" +#include "flutter/fml/paths.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/switches.h" +#include "flutter/shell/common/thread_host.h" +#include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/synchronization/waitable_event.h" +#include "third_party/dart/runtime/bin/embedded_dart_io.h" + +#ifdef ERROR +#undef ERROR +#endif + +namespace shell { + +// Checks whether the engine's main Dart isolate has no pending work. If so, +// then exit the given message loop. +class ScriptCompletionTaskObserver { + public: + ScriptCompletionTaskObserver(Shell& shell, + fxl::RefPtr main_task_runner, + bool run_forever) + : engine_(shell.GetEngine()), + main_task_runner_(std::move(main_task_runner)), + run_forever_(run_forever) {} + + int GetExitCodeForLastError() const { + // Exit codes used by the Dart command line tool. + const int kApiErrorExitCode = 253; + const int kCompilationErrorExitCode = 254; + const int kErrorExitCode = 255; + switch (last_error_) { + case tonic::kCompilationErrorType: + return kCompilationErrorExitCode; + case tonic::kApiErrorType: + return kApiErrorExitCode; + case tonic::kUnknownErrorType: + return kErrorExitCode; + default: + return 0; + } + } + + void DidProcessTask() { + if (engine_) { + last_error_ = engine_->GetUIIsolateLastError(); + if (engine_->UIIsolateHasLivePorts()) { + // The UI isolate still has live ports and is running. Nothing to do + // just yet. + return; + } + } + + if (run_forever_) { + // We need this script to run forever. We have already recorded the last + // error. Keep going. + return; + } + + if (!has_terminated) { + // Only try to terminate the loop once. + has_terminated = true; + main_task_runner_->PostTask( + []() { fml::MessageLoop::GetCurrent().Terminate(); }); + } + } + + private: + fml::WeakPtr engine_; + fxl::RefPtr main_task_runner_; + bool run_forever_ = false; + tonic::DartErrorHandleType last_error_ = tonic::kUnknownErrorType; + bool has_terminated = false; + + FXL_DISALLOW_COPY_AND_ASSIGN(ScriptCompletionTaskObserver); +}; + +int RunTester(const blink::Settings& settings, bool run_forever) { + const auto thread_label = "io.flutter.test"; + + fml::MessageLoop::EnsureInitializedForCurrentThread(); + + auto current_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); + + // Setup a single threaded test runner configuration. + const blink::TaskRunners task_runners(thread_label, // dart thread label + current_task_runner, // platform + current_task_runner, // gpu + current_task_runner, // ui + current_task_runner // io + ); + + Shell::CreateCallback on_create_platform_view = + [](Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); + }; + + Shell::CreateCallback on_create_rasterizer = [](Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); + }; + + auto shell = Shell::Create(task_runners, // + settings, // + on_create_platform_view, // + on_create_rasterizer // + ); + + if (!shell || !shell->IsSetup()) { + FXL_LOG(ERROR) << "Could not setup the shell."; + return EXIT_FAILURE; + } + + auto isolate_configuration = IsolateConfiguration::CreateForSource( + settings.main_dart_file_path, settings.packages_file_path); + + if (!isolate_configuration) { + FXL_LOG(ERROR) << "Could create isolate configuration."; + return EXIT_FAILURE; + } + + auto asset_manager = fxl::MakeRefCounted(); + asset_manager->PushBack(std::make_unique( + fml::Duplicate(settings.assets_dir))); + asset_manager->PushBack( + std::make_unique(fml::OpenFile( + settings.assets_path.c_str(), fml::OpenPermission::kRead, true))); + + RunConfiguration run_configuration(std::move(isolate_configuration), + std::move(asset_manager)); + + // The script completion task observer that will be installed on the UI thread + // that watched if the engine has any live ports. + ScriptCompletionTaskObserver completion_observer( + *shell, // a valid shell + fml::MessageLoop::GetCurrent() + .GetTaskRunner(), // the message loop to terminate + run_forever // should the exit be ignored + ); + + bool engine_did_run = false; + + shell->GetTaskRunners().GetUITaskRunner()->PostTask(fxl::MakeCopyable( + [&completion_observer, engine = shell->GetEngine(), + config = std::move(run_configuration), &engine_did_run]() mutable { + fml::MessageLoop::GetCurrent().AddTaskObserver( + reinterpret_cast(&completion_observer), + [&completion_observer]() { completion_observer.DidProcessTask(); }); + if (engine->Run(std::move(config))) { + engine_did_run = true; + + blink::ViewportMetrics metrics; + metrics.device_pixel_ratio = 3.0; + metrics.physical_width = 2400; // 800 at 3x resolution + metrics.physical_height = 1800; // 600 at 3x resolution + engine->SetViewportMetrics(metrics); + + } else { + FXL_DLOG(ERROR) << "Could not launch the engine with configuration."; + } + })); + + // Run the message loop and wait for the script to do its thing. + fml::MessageLoop::GetCurrent().Run(); + + // Cleanup the completion observer synchronously as it is living on the + // stack. + fxl::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask( + shell->GetTaskRunners().GetUITaskRunner(), + [&latch, &completion_observer] { + fml::MessageLoop::GetCurrent().RemoveTaskObserver( + reinterpret_cast(&completion_observer)); + latch.Signal(); + }); + latch.Wait(); + + if (!engine_did_run) { + // If the engine itself didn't have a chance to run, there is no point in + // asking it if there was an error. Signal a failure unconditionally. + return EXIT_FAILURE; + } + + return completion_observer.GetExitCodeForLastError(); +} + +} // namespace shell + +int main(int argc, char* argv[]) { + dart::bin::SetExecutableName(argv[0]); + dart::bin::SetExecutableArguments(argc - 1, argv); + + auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); + + if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { + shell::PrintUsage("flutter_tester"); + return EXIT_SUCCESS; + } + + auto settings = shell::SettingsFromCommandLine(command_line); + if (command_line.positional_args().size() > 0) { + // The tester may not use the switch for the main dart file path. Specifying + // it as a positional argument instead. + settings.main_dart_file_path = command_line.positional_args()[0]; + } + + if (settings.main_dart_file_path.size() == 0) { + FXL_LOG(ERROR) << "Main dart file path not specified."; + return EXIT_FAILURE; + } + + settings.icu_data_path = "icudtl.dat"; + + settings.kernel_snapshot_path = + fml::paths::JoinPaths({settings.assets_path, "platform.dill"}); + + // The tools that read logs get confused if there is a log tag specified. + settings.log_tag = ""; + + settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { + fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); + }; + + settings.task_observer_remove = [](intptr_t key) { + fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); + }; + + return shell::RunTester( + settings, + command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever))); +} diff --git a/shell/testing/testing.cc b/shell/testing/testing.cc deleted file mode 100644 index 13a3ab5be3d93..0000000000000 --- a/shell/testing/testing.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 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. - -#include "flutter/shell/testing/testing.h" - -#include "flutter/shell/common/switches.h" -#include "flutter/shell/testing/test_runner.h" - -namespace shell { - -bool InitForTesting(const fxl::CommandLine& command_line) { - TestRunner::TestDescriptor test; - test.packages = command_line.GetOptionValueWithDefault( - FlagForSwitch(Switch::Packages), ""); - auto args = command_line.positional_args(); - if (args.empty()) - return false; - test.path = args[0]; - TestRunner::Shared().Run(test); - return true; -} - -} // namespace shell diff --git a/shell/testing/testing.h b/shell/testing/testing.h deleted file mode 100644 index 99f8b4fe983de..0000000000000 --- a/shell/testing/testing.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 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 SHELL_TESTING_TESTING_H_ -#define SHELL_TESTING_TESTING_H_ - -#include "lib/fxl/command_line.h" - -namespace shell { - -bool InitForTesting(const fxl::CommandLine& command_line); - -} // namespace shell - -#endif // SHELL_TESTING_TESTING_H_ diff --git a/sky/engine/platform/SharedBuffer.cpp b/sky/engine/platform/SharedBuffer.cpp index 8577ab16f2938..bc94f22e97ce6 100644 --- a/sky/engine/platform/SharedBuffer.cpp +++ b/sky/engine/platform/SharedBuffer.cpp @@ -26,7 +26,6 @@ #include "flutter/sky/engine/platform/SharedBuffer.h" -#include "flutter/common/threads.h" #include "flutter/sky/engine/public/platform/Platform.h" #include "flutter/sky/engine/wtf/unicode/UTF8.h" #include "flutter/sky/engine/wtf/unicode/Unicode.h" diff --git a/sky/engine/platform/fonts/FontFallbackList.cpp b/sky/engine/platform/fonts/FontFallbackList.cpp index 177f161adaa7e..4786d65e0d7ad 100644 --- a/sky/engine/platform/fonts/FontFallbackList.cpp +++ b/sky/engine/platform/fonts/FontFallbackList.cpp @@ -37,6 +37,11 @@ namespace blink { +bool gUseTestFonts = false; +void FontFallbackList::SetUseTestFonts(bool useTestFonts) { + gUseTestFonts = useTestFonts; +} + FontFallbackList::FontFallbackList() : m_pageZero(0), m_cachedPrimarySimpleFontData(0), @@ -45,7 +50,8 @@ FontFallbackList::FontFallbackList() m_familyIndex(0), m_generation(FontCache::fontCache()->generation()), m_pitch(UnknownPitch), - m_hasLoadingFallback(false) {} + m_hasLoadingFallback(false), + m_useTestFonts(gUseTestFonts) {} void FontFallbackList::invalidate(PassRefPtr fontSelector) { releaseFontData(); @@ -193,7 +199,7 @@ PassRefPtr FontFallbackList::getFontData( const FontFamily* currFamily = startFamily; while (currFamily && !result) { familyIndex++; - if (currFamily->family().length() || Settings::Get().use_test_fonts) { + if (currFamily->family().length() || m_useTestFonts) { if (m_fontSelector) result = m_fontSelector->getFontData(fontDescription, currFamily->family()); diff --git a/sky/engine/platform/fonts/FontFallbackList.h b/sky/engine/platform/fonts/FontFallbackList.h index fdac27e5013bd..3331387968edc 100644 --- a/sky/engine/platform/fonts/FontFallbackList.h +++ b/sky/engine/platform/fonts/FontFallbackList.h @@ -103,6 +103,8 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted { m_pageZero = node; } + static void SetUseTestFonts(bool useTestFonts); + private: FontFallbackList(); @@ -125,6 +127,7 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted { unsigned short m_generation; mutable unsigned m_pitch : 3; // Pitch mutable bool m_hasLoadingFallback : 1; + bool m_useTestFonts = false; }; } // namespace blink diff --git a/sky/engine/web/Sky.cpp b/sky/engine/web/Sky.cpp index e90539e96cf87..52c6243743d7b 100644 --- a/sky/engine/web/Sky.cpp +++ b/sky/engine/web/Sky.cpp @@ -53,56 +53,6 @@ namespace blink { -namespace { - -void didProcessTask() { - tonic::DartMicrotaskQueue::GetForCurrentThread()->RunMicrotasks(); - // FIXME: Report memory usage to dart? -} - -#if defined(OS_FUCHSIA) - -void addMessageLoopObservers() { - fsl::MessageLoop::GetCurrent()->SetAfterTaskCallback(didProcessTask); -} - -void removeMessageLoopObservers() { - fsl::MessageLoop::GetCurrent()->ClearAfterTaskCallback(); -} - -#else // defined(OS_FUCHSIA) - -class RunMicrotasksTaskObserver : public fml::TaskObserver { - public: - RunMicrotasksTaskObserver() = default; - - ~RunMicrotasksTaskObserver() override = default; - - void DidProcessTask() override { didProcessTask(); } -}; - -// FIXME(chinmaygarde): The awkward use of the global here is be cause we cannot -// introduce the fml::TaskObserver subclass in common code because Fuchsia does -// not support the same. Unify the API and remove hack. -static RunMicrotasksTaskObserver* g_run_microtasks_task_observer = nullptr; - -void addMessageLoopObservers() { - g_run_microtasks_task_observer = new RunMicrotasksTaskObserver(); - fml::MessageLoop::GetCurrent().AddTaskObserver( - g_run_microtasks_task_observer); -} - -void removeMessageLoopObservers() { - fml::MessageLoop::GetCurrent().RemoveTaskObserver( - g_run_microtasks_task_observer); - delete g_run_microtasks_task_observer; - g_run_microtasks_task_observer = nullptr; -} - -#endif // defined(OS_FUCHSIA) - -} // namespace - // Make sure we are not re-initialized in the same address space. // Doing so may cause hard to reproduce crashes. static bool s_webKitInitialized = false; @@ -130,15 +80,9 @@ void InitEngine(Platform* platform) { // the initialization thread-safe, but given that so many code paths use // this, initializing this lazily probably doesn't buy us much. WTF::UTF8Encoding(); - - tonic::DartMicrotaskQueue::StartForCurrentThread(); - addMessageLoopObservers(); } void ShutdownEngine() { - removeMessageLoopObservers(); - tonic::DartMicrotaskQueue::GetForCurrentThread()->Destroy(); - // FIXME: Shutdown dart? CoreInitializer::shutdown(); diff --git a/synchronization/BUILD.gn b/synchronization/BUILD.gn index 977a571c8da30..9ee7680cc1160 100644 --- a/synchronization/BUILD.gn +++ b/synchronization/BUILD.gn @@ -4,16 +4,13 @@ source_set("synchronization") { sources = [ - "debug_thread_checker.h", "pipeline.cc", "pipeline.h", "semaphore.cc", "semaphore.h", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] public_deps = [ "$flutter_root/glue", diff --git a/synchronization/debug_thread_checker.h b/synchronization/debug_thread_checker.h deleted file mode 100644 index 69614eb89d217..0000000000000 --- a/synchronization/debug_thread_checker.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2016 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_SYNCHRONIZATION_DEBUG_THREAD_CHECKER_H_ -#define FLUTTER_SYNCHRONIZATION_DEBUG_THREAD_CHECKER_H_ - -#ifndef NDEBUG - -#include -#include "lib/fxl/synchronization/thread_checker.h" - -#define FLUTTER_THREAD_CHECKER_DECLARE(x) ::fxl::ThreadChecker x; - -#define FLUTTER_THREAD_CHECKER_CHECK(x) FXL_CHECK(x.IsCreationThreadCurrent()); - -#else // NDEBUG - -#define FLUTTER_THREAD_CHECKER_DECLARE(x) - -#define FLUTTER_THREAD_CHECKER_CHECK(x) - -#endif // NDEBUG - -#endif // FLUTTER_SYNCHRONIZATION_DEBUG_THREAD_CHECKER_H_ diff --git a/synchronization/semaphore.cc b/synchronization/semaphore.cc index c6e0bdf9e2d53..4dc5f6220e350 100644 --- a/synchronization/semaphore.cc +++ b/synchronization/semaphore.cc @@ -15,9 +15,12 @@ namespace flutter { class PlatformSemaphore { public: explicit PlatformSemaphore(uint32_t count) - : _sem(dispatch_semaphore_create(count)) {} + : _sem(dispatch_semaphore_create(count)), _initial(count) {} ~PlatformSemaphore() { + for (uint32_t i = 0; i < _initial; ++i) { + Signal(); + } if (_sem != nullptr) { dispatch_release(reinterpret_cast(_sem)); _sem = nullptr; @@ -42,6 +45,7 @@ class PlatformSemaphore { private: dispatch_semaphore_t _sem; + const uint32_t _initial; FXL_DISALLOW_COPY_AND_ASSIGN(PlatformSemaphore); }; diff --git a/testing/BUILD.gn b/testing/BUILD.gn index 3927e71cfc0e4..a65311bfaeb7c 100644 --- a/testing/BUILD.gn +++ b/testing/BUILD.gn @@ -9,9 +9,13 @@ source_set("testing") { "$flutter_root/testing/run_all_unittests.cc", "$flutter_root/testing/testing.cc", "$flutter_root/testing/testing.h", + "$flutter_root/testing/thread_test.cc", + "$flutter_root/testing/thread_test.h", ] public_deps = [ + "$flutter_root/fml", + "//garnet/public/lib/fxl", "//third_party/googletest:gtest", ] diff --git a/testing/thread_test.cc b/testing/thread_test.cc new file mode 100644 index 0000000000000..1306f37678fbe --- /dev/null +++ b/testing/thread_test.cc @@ -0,0 +1,33 @@ +// 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. + +#define FML_USED_ON_EMBEDDER + +#include "flutter/testing/thread_test.h" + +namespace testing { + +void ThreadTest::SetUp() { + thread_ = std::make_unique(); + thread_task_runner_ = thread_->GetTaskRunner(); + + fml::MessageLoop::EnsureInitializedForCurrentThread(); + current_task_runner_ = fml::MessageLoop::GetCurrent().GetTaskRunner(); +} + +void ThreadTest::TearDown() { + thread_task_runner_ = nullptr; + thread_ = nullptr; + current_task_runner_ = nullptr; +} + +fxl::RefPtr ThreadTest::GetCurrentTaskRunner() { + return current_task_runner_; +} + +fxl::RefPtr ThreadTest::GetThreadTaskRunner() { + return thread_task_runner_; +} + +} // namespace testing diff --git a/testing/thread_test.h b/testing/thread_test.h new file mode 100644 index 0000000000000..511d09c978858 --- /dev/null +++ b/testing/thread_test.h @@ -0,0 +1,37 @@ +// 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_TESTING_THREAD_TEST_H_ +#define FLUTTER_TESTING_THREAD_TEST_H_ + +#include + +#include "flutter/fml/message_loop.h" +#include "flutter/fml/task_runner.h" +#include "flutter/fml/thread.h" +#include "gtest/gtest.h" +#include "lib/fxl/macros.h" + +namespace testing { + +class ThreadTest : public Test { + public: + fxl::RefPtr GetCurrentTaskRunner(); + + fxl::RefPtr GetThreadTaskRunner(); + + protected: + void SetUp() override; + + void TearDown() override; + + private: + std::unique_ptr thread_; + fxl::RefPtr thread_task_runner_; + fxl::RefPtr current_task_runner_; +}; + +} // namespace testing + +#endif // FLUTTER_TESTING_THREAD_TEST_H_ diff --git a/tools/gn b/tools/gn index ea7071ac0a474..b4b15f99f1d4f 100755 --- a/tools/gn +++ b/tools/gn @@ -232,6 +232,10 @@ def main(argv): # On the Mac, also generate Xcode projects for ease of editing. command.append('--ide=xcode') + if sys.platform.startswith('win'): + # On Windows, also generate Visual Studio project for ease of editing. + command.append('--ide=vs') + gn_args = to_command_line(to_gn_args(args)) out_dir = get_out_dir(args) print "gn gen --check in %s" % out_dir diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index 8749f6880dbf4..b15c608425095 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -1059,14 +1059,10 @@ USED LICENSES: ==================================================================================================== LIBRARY: engine LIBRARY: txt -ORIGIN: ../../../flutter/content_handler/service_protocol_hooks.cc + ../../../LICENSE +ORIGIN: ../../../flutter/content_handler/session_connection.cc + ../../../LICENSE TYPE: LicenseType.bsd -FILE: ../../../flutter/content_handler/service_protocol_hooks.cc -FILE: ../../../flutter/content_handler/service_protocol_hooks.h FILE: ../../../flutter/content_handler/session_connection.cc FILE: ../../../flutter/content_handler/session_connection.h -FILE: ../../../flutter/content_handler/vulkan_rasterizer.cc -FILE: ../../../flutter/content_handler/vulkan_rasterizer.h FILE: ../../../flutter/content_handler/vulkan_surface_producer.cc FILE: ../../../flutter/content_handler/vulkan_surface_producer.h FILE: ../../../flutter/flow/debug_print.cc @@ -1126,7 +1122,6 @@ FILE: ../../../flutter/fml/platform/win/mapping_win.cc FILE: ../../../flutter/fml/platform/win/message_loop_win.cc FILE: ../../../flutter/fml/platform/win/message_loop_win.h FILE: ../../../flutter/fml/platform/win/paths_win.cc -FILE: ../../../flutter/fml/task_observer.h FILE: ../../../flutter/fml/task_runner.cc FILE: ../../../flutter/fml/task_runner.h FILE: ../../../flutter/fml/thread.cc @@ -1142,13 +1137,10 @@ FILE: ../../../flutter/lib/ui/painting/codec.cc FILE: ../../../flutter/lib/ui/painting/codec.h FILE: ../../../flutter/lib/ui/painting/frame_info.cc FILE: ../../../flutter/lib/ui/painting/frame_info.h -FILE: ../../../flutter/lib/ui/painting/utils.cc FILE: ../../../flutter/lib/ui/painting/vertices.cc FILE: ../../../flutter/lib/ui/painting/vertices.h FILE: ../../../flutter/lib/ui/text/font_collection.cc FILE: ../../../flutter/lib/ui/text/font_collection.h -FILE: ../../../flutter/shell/common/null_platform_view.cc -FILE: ../../../flutter/shell/common/null_platform_view.h FILE: ../../../flutter/shell/gpu/gpu_surface_software.cc FILE: ../../../flutter/shell/gpu/gpu_surface_software.h FILE: ../../../flutter/shell/platform/android/android_external_texture_gl.cc @@ -1195,8 +1187,6 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterStandar FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterStandardCodec_Internal.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUmbrellaImport.m FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_codecs_unittest.mm -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_standard_codec_unittest.mm FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.h FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.mm @@ -1563,7 +1553,6 @@ FILE: ../../../flutter/shell/common/skia_event_tracer_impl.cc FILE: ../../../flutter/shell/platform/android/apk_asset_provider.cc FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/JSONUtil.java FILE: ../../../flutter/shell/platform/darwin/desktop/Info.plist -FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_mac.xib FILE: ../../../flutter/shell/platform/darwin/ios/framework/Flutter.podspec FILE: ../../../flutter/shell/platform/darwin/ios/framework/Info.plist FILE: ../../../flutter/shell/platform/darwin/ios/framework/module.modulemap @@ -1638,17 +1627,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: engine -ORIGIN: ../../../flutter/assets/asset_provider.h + ../../../LICENSE +ORIGIN: ../../../flutter/assets/asset_manager.cc + ../../../LICENSE TYPE: LicenseType.bsd -FILE: ../../../flutter/assets/asset_provider.h -FILE: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_locations.dart -FILE: ../../../flutter/lib/ui/painting/image_encoding.cc -FILE: ../../../flutter/lib/ui/painting/image_encoding.h -FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm +FILE: ../../../flutter/assets/asset_manager.cc +FILE: ../../../flutter/assets/asset_manager.h +FILE: ../../../flutter/assets/asset_resolver.h +FILE: ../../../flutter/common/task_runners.cc +FILE: ../../../flutter/common/task_runners.h +FILE: ../../../flutter/flow/layers/default_layer_builder.cc +FILE: ../../../flutter/flow/layers/default_layer_builder.h +FILE: ../../../flutter/flow/layers/layer_builder.cc +FILE: ../../../flutter/flow/layers/layer_builder.h +FILE: ../../../flutter/flow/skia_gpu_object.cc +FILE: ../../../flutter/flow/skia_gpu_object.h +FILE: ../../../flutter/runtime/dart_isolate.cc +FILE: ../../../flutter/runtime/dart_isolate.h +FILE: ../../../flutter/runtime/dart_isolate_unittests.cc +FILE: ../../../flutter/runtime/dart_snapshot.cc +FILE: ../../../flutter/runtime/dart_snapshot.h +FILE: ../../../flutter/runtime/dart_snapshot_buffer.cc +FILE: ../../../flutter/runtime/dart_snapshot_buffer.h +FILE: ../../../flutter/runtime/dart_vm.cc +FILE: ../../../flutter/runtime/dart_vm.h +FILE: ../../../flutter/runtime/dart_vm_unittests.cc +FILE: ../../../flutter/runtime/service_protocol.cc +FILE: ../../../flutter/runtime/service_protocol.h +FILE: ../../../flutter/shell/common/io_manager.cc +FILE: ../../../flutter/shell/common/io_manager.h +FILE: ../../../flutter/shell/common/run_configuration.cc +FILE: ../../../flutter/shell/common/run_configuration.h +FILE: ../../../flutter/shell/common/shell_unittests.cc +FILE: ../../../flutter/shell/common/thread_host.cc +FILE: ../../../flutter/shell/common/thread_host.h +FILE: ../../../flutter/shell/platform/darwin/common/command_line.h +FILE: ../../../flutter/shell/platform/darwin/common/command_line.mm +FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_application_delegate.h +FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_application_delegate.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h +FILE: ../../../flutter/shell/platform/embedder/embedder.h +FILE: ../../../flutter/shell/platform/embedder/embedder_engine.cc +FILE: ../../../flutter/shell/platform/embedder/embedder_engine.h ---------------------------------------------------------------------------------------------------- -Copyright 2018 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -1683,23 +1703,10 @@ ORIGIN: ../../../flutter/assets/directory_asset_bundle.cc + ../../../LICENSE TYPE: LicenseType.bsd FILE: ../../../flutter/assets/directory_asset_bundle.cc FILE: ../../../flutter/assets/directory_asset_bundle.h -FILE: ../../../flutter/assets/unzipper_provider.cc -FILE: ../../../flutter/assets/unzipper_provider.h FILE: ../../../flutter/assets/zip_asset_store.cc FILE: ../../../flutter/assets/zip_asset_store.h FILE: ../../../flutter/common/settings.cc FILE: ../../../flutter/common/settings.h -FILE: ../../../flutter/common/threads.cc -FILE: ../../../flutter/common/threads.h -FILE: ../../../flutter/content_handler/app.cc -FILE: ../../../flutter/content_handler/app.h -FILE: ../../../flutter/content_handler/application_controller_impl.cc -FILE: ../../../flutter/content_handler/application_controller_impl.h -FILE: ../../../flutter/content_handler/main.cc -FILE: ../../../flutter/content_handler/rasterizer.cc -FILE: ../../../flutter/content_handler/rasterizer.h -FILE: ../../../flutter/content_handler/runtime_holder.cc -FILE: ../../../flutter/content_handler/runtime_holder.h FILE: ../../../flutter/flow/export_node.cc FILE: ../../../flutter/flow/layers/backdrop_filter_layer.cc FILE: ../../../flutter/flow/layers/backdrop_filter_layer.h @@ -1707,7 +1714,6 @@ FILE: ../../../flutter/flow/layers/child_scene_layer.cc FILE: ../../../flutter/flow/layers/child_scene_layer.h FILE: ../../../flutter/flow/layers/shader_mask_layer.cc FILE: ../../../flutter/flow/layers/shader_mask_layer.h -FILE: ../../../flutter/flow/process_info.h FILE: ../../../flutter/flow/raster_cache.cc FILE: ../../../flutter/flow/raster_cache.h FILE: ../../../flutter/flow/scene_update_context.cc @@ -1718,9 +1724,6 @@ FILE: ../../../flutter/glue/stack_trace_fuchsia.cc FILE: ../../../flutter/glue/trace_event.h FILE: ../../../flutter/lib/ui/painting/image_filter.cc FILE: ../../../flutter/lib/ui/painting/image_filter.h -FILE: ../../../flutter/lib/ui/painting/resource_context.cc -FILE: ../../../flutter/lib/ui/painting/resource_context.h -FILE: ../../../flutter/lib/ui/painting/utils.h FILE: ../../../flutter/lib/ui/semantics.dart FILE: ../../../flutter/lib/ui/semantics/semantics_node.cc FILE: ../../../flutter/lib/ui/semantics/semantics_node.h @@ -1742,18 +1745,13 @@ FILE: ../../../flutter/runtime/asset_font_selector.cc FILE: ../../../flutter/runtime/asset_font_selector.h FILE: ../../../flutter/runtime/embedder_resources.cc FILE: ../../../flutter/runtime/embedder_resources.h -FILE: ../../../flutter/runtime/runtime_init.cc -FILE: ../../../flutter/runtime/runtime_init.h +FILE: ../../../flutter/runtime/fixtures/simple_main.dart FILE: ../../../flutter/runtime/start_up.cc FILE: ../../../flutter/runtime/start_up.h FILE: ../../../flutter/runtime/test_font_data.cc FILE: ../../../flutter/runtime/test_font_data.h FILE: ../../../flutter/runtime/test_font_selector.cc FILE: ../../../flutter/runtime/test_font_selector.h -FILE: ../../../flutter/shell/common/null_rasterizer.cc -FILE: ../../../flutter/shell/common/null_rasterizer.h -FILE: ../../../flutter/shell/common/platform_view_service_protocol.cc -FILE: ../../../flutter/shell/common/platform_view_service_protocol.h FILE: ../../../flutter/shell/common/skia_event_tracer_impl.h FILE: ../../../flutter/shell/common/surface.cc FILE: ../../../flutter/shell/common/surface.h @@ -1782,8 +1780,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h FILE: ../../../flutter/shell/platform/darwin/common/buffer_conversions.mm -FILE: ../../../flutter/shell/platform/darwin/common/process_info_mac.cc -FILE: ../../../flutter/shell/platform/darwin/common/process_info_mac.h FILE: ../../../flutter/shell/platform/darwin/desktop/vsync_waiter_mac.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h @@ -1792,8 +1788,6 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterMacros FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h @@ -1816,7 +1810,6 @@ FILE: ../../../flutter/sky/engine/platform/text/ICUError.cpp FILE: ../../../flutter/sky/engine/platform/text/ICUError.h FILE: ../../../flutter/sky/engine/platform/text/TextBox.h FILE: ../../../flutter/sky/packages/flutter_services/lib/empty.dart -FILE: ../../../flutter/synchronization/debug_thread_checker.h FILE: ../../../flutter/synchronization/pipeline.cc FILE: ../../../flutter/synchronization/pipeline.h FILE: ../../../flutter/synchronization/semaphore.cc @@ -1884,15 +1877,68 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: engine -ORIGIN: ../../../flutter/flow/layers/default_layer_builder.cc + ../../../LICENSE +ORIGIN: ../../../flutter/content_handler/application.cc + ../../../garnet/LICENSE TYPE: LicenseType.bsd -FILE: ../../../flutter/flow/layers/default_layer_builder.cc -FILE: ../../../flutter/flow/layers/default_layer_builder.h -FILE: ../../../flutter/flow/layers/layer_builder.cc -FILE: ../../../flutter/flow/layers/layer_builder.h -FILE: ../../../flutter/shell/platform/embedder/embedder.h +FILE: ../../../flutter/content_handler/application.cc +FILE: ../../../flutter/content_handler/application.h +FILE: ../../../flutter/content_handler/application_runner.cc +FILE: ../../../flutter/content_handler/application_runner.h +FILE: ../../../flutter/content_handler/compositor_context.cc +FILE: ../../../flutter/content_handler/compositor_context.h +FILE: ../../../flutter/content_handler/engine.cc +FILE: ../../../flutter/content_handler/engine.h +FILE: ../../../flutter/content_handler/isolate_configurator.cc +FILE: ../../../flutter/content_handler/isolate_configurator.h +FILE: ../../../flutter/content_handler/main.cc +FILE: ../../../flutter/content_handler/platform_view.cc +FILE: ../../../flutter/content_handler/platform_view.h +FILE: ../../../flutter/content_handler/surface.cc +FILE: ../../../flutter/content_handler/surface.h +FILE: ../../../flutter/content_handler/task_observers.cc +FILE: ../../../flutter/content_handler/task_observers.h +FILE: ../../../flutter/content_handler/unique_fdio_ns.h ---------------------------------------------------------------------------------------------------- -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2018 The Fuchsia Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + +==================================================================================================== +LIBRARY: engine +ORIGIN: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_locations.dart + ../../../LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_locations.dart +FILE: ../../../flutter/lib/ui/painting/image_encoding.cc +FILE: ../../../flutter/lib/ui/painting/image_encoding.h +FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm +---------------------------------------------------------------------------------------------------- +Copyright 2018 The Chromium Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -1957,6 +2003,62 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: engine +ORIGIN: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc + ../../../LICENSE +TYPE: LicenseType.bsd +FILE: ../../../flutter/fml/file.h +FILE: ../../../flutter/fml/macros.h +FILE: ../../../flutter/fml/mapping.cc +FILE: ../../../flutter/fml/native_library.h +FILE: ../../../flutter/fml/paths.cc +FILE: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc +FILE: ../../../flutter/fml/platform/posix/file_posix.cc +FILE: ../../../flutter/fml/platform/posix/native_library_posix.cc +FILE: ../../../flutter/fml/platform/win/file_win.cc +FILE: ../../../flutter/fml/platform/win/native_library_win.cc +FILE: ../../../flutter/fml/platform/win/wstring_conversion.h +FILE: ../../../flutter/fml/unique_fd.cc +FILE: ../../../flutter/fml/unique_fd.h +FILE: ../../../flutter/fml/unique_object.h +FILE: ../../../flutter/shell/common/isolate_configuration.cc +FILE: ../../../flutter/shell/common/isolate_configuration.h +FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc +FILE: ../../../flutter/shell/platform/android/android_shell_holder.h +FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc +FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm +---------------------------------------------------------------------------------------------------- +Copyright 2018 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================================================== + ==================================================================================================== LIBRARY: engine ORIGIN: ../../../flutter/lib/ui/painting/image.cc + ../../../LICENSE @@ -9873,10 +9975,6 @@ FILE: ../../../flutter/lib/ui/window.dart FILE: ../../../flutter/lib/ui/window/pointer_data.cc FILE: ../../../flutter/lib/ui/window/pointer_data_packet.cc FILE: ../../../flutter/lib/ui/window/window.cc -FILE: ../../../flutter/runtime/dart_controller.cc -FILE: ../../../flutter/runtime/dart_controller.h -FILE: ../../../flutter/runtime/dart_init.cc -FILE: ../../../flutter/runtime/dart_init.h FILE: ../../../flutter/runtime/dart_service_isolate.cc FILE: ../../../flutter/runtime/dart_service_isolate.h FILE: ../../../flutter/runtime/platform_impl.cc @@ -9896,13 +9994,9 @@ FILE: ../../../flutter/shell/common/rasterizer.cc FILE: ../../../flutter/shell/common/rasterizer.h FILE: ../../../flutter/shell/common/shell.cc FILE: ../../../flutter/shell/common/shell.h -FILE: ../../../flutter/shell/common/tracing_controller.cc -FILE: ../../../flutter/shell/common/tracing_controller.h FILE: ../../../flutter/shell/common/vsync_waiter.cc FILE: ../../../flutter/shell/common/vsync_waiter.h FILE: ../../../flutter/shell/common/vsync_waiter_fallback.h -FILE: ../../../flutter/shell/gpu/gpu_rasterizer.cc -FILE: ../../../flutter/shell/gpu/gpu_rasterizer.h FILE: ../../../flutter/shell/platform/android/AndroidManifest.xml FILE: ../../../flutter/shell/platform/android/flutter_main.cc FILE: ../../../flutter/shell/platform/android/flutter_main.h @@ -9915,12 +10009,6 @@ FILE: ../../../flutter/shell/platform/android/library_loader.cc FILE: ../../../flutter/shell/platform/android/platform_view_android.cc FILE: ../../../flutter/shell/platform/android/platform_view_android.h FILE: ../../../flutter/shell/platform/darwin/common/buffer_conversions.h -FILE: ../../../flutter/shell/platform/darwin/common/platform_mac.h -FILE: ../../../flutter/shell/platform/darwin/common/platform_mac.mm -FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_app_delegate.h -FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_app_delegate.m -FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_application.h -FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_application.mm FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_window.h FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_window.mm FILE: ../../../flutter/shell/platform/darwin/desktop/main_mac.mm @@ -9930,8 +10018,6 @@ FILE: ../../../flutter/shell/platform/darwin/desktop/vsync_waiter_mac.cc FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm -FILE: ../../../flutter/shell/platform/linux/main_linux.cc -FILE: ../../../flutter/shell/platform/win/main_win.cc FILE: ../../../flutter/sky/engine/wtf/Allocator.h FILE: ../../../flutter/sky/engine/wtf/MakeUnique.h ---------------------------------------------------------------------------------------------------- @@ -9968,6 +10054,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIBRARY: engine ORIGIN: ../../../topaz/LICENSE TYPE: LicenseType.bsd +FILE: ../../../flutter/fml/memory/thread_checker.h FILE: ../../../flutter/fml/memory/weak_ptr.h FILE: ../../../flutter/fml/memory/weak_ptr_internal.cc FILE: ../../../flutter/fml/memory/weak_ptr_internal.h @@ -10001,4 +10088,4 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -Total license count: 216 +Total license count: 218