From caf32d5b28cbc4599faf506ea4bbb57c260a7a0d Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 29 Oct 2020 13:13:03 -0700 Subject: [PATCH] Add a proc table version of embedder API (#21813) --- BUILD.gn | 1 + ci/licenses_golden/licenses_flutter | 3 +- shell/platform/embedder/BUILD.gn | 37 ++- shell/platform/embedder/embedder.cc | 56 +++- shell/platform/embedder/embedder.h | 267 ++++++++++++++---- ...safe_access.h => embedder_struct_macros.h} | 24 +- .../platform/embedder/embedder_thread_host.cc | 2 +- .../test_utils/proc_table_replacement.h | 23 ++ .../tests/embedder_unittests_proctable.cc | 62 ++++ testing/run_tests.py | 1 + 10 files changed, 414 insertions(+), 62 deletions(-) rename shell/platform/embedder/{embedder_safe_access.h => embedder_struct_macros.h} (63%) create mode 100644 shell/platform/embedder/test_utils/proc_table_replacement.h create mode 100644 shell/platform/embedder/tests/embedder_unittests_proctable.cc diff --git a/BUILD.gn b/BUILD.gn index 82575d2ff3755..edbeb6803c3e5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -95,6 +95,7 @@ group("flutter") { "//flutter/lib/ui:ui_unittests", "//flutter/runtime:runtime_unittests", "//flutter/shell/common:shell_unittests", + "//flutter/shell/platform/embedder:embedder_proctable_unittests", "//flutter/shell/platform/embedder:embedder_unittests", "//flutter/testing:testing_unittests", "//flutter/third_party/txt:txt_unittests", diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 101756014be9c..f13271aa91373 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1093,7 +1093,7 @@ FILE: ../../../flutter/shell/platform/embedder/embedder_render_target.cc FILE: ../../../flutter/shell/platform/embedder/embedder_render_target.h FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.cc FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.h -FILE: ../../../flutter/shell/platform/embedder/embedder_safe_access.h +FILE: ../../../flutter/shell/platform/embedder/embedder_struct_macros.h FILE: ../../../flutter/shell/platform/embedder/embedder_surface.cc FILE: ../../../flutter/shell/platform/embedder/embedder_surface.h FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.cc @@ -1121,6 +1121,7 @@ FILE: ../../../flutter/shell/platform/embedder/fixtures/verifyb143464703.png FILE: ../../../flutter/shell/platform/embedder/fixtures/verifyb143464703_soft_noxform.png FILE: ../../../flutter/shell/platform/embedder/platform_view_embedder.cc FILE: ../../../flutter/shell/platform/embedder/platform_view_embedder.h +FILE: ../../../flutter/shell/platform/embedder/test_utils/proc_table_replacement.h FILE: ../../../flutter/shell/platform/embedder/vsync_waiter_embedder.cc FILE: ../../../flutter/shell/platform/embedder/vsync_waiter_embedder.h FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/fuchsia/lib/fuchsia.dart diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index 66bc980d9e104..0ad51fbfc74b1 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -48,7 +48,7 @@ template("embedder_source_set") { "embedder_render_target.h", "embedder_render_target_cache.cc", "embedder_render_target_cache.h", - "embedder_safe_access.h", + "embedder_struct_macros.h", "embedder_surface.cc", "embedder_surface.h", "embedder_surface_software.cc", @@ -110,6 +110,14 @@ source_set("embedder_headers") { public_configs = [ "//flutter:config" ] } +source_set("embedder_test_utils") { + public = [ "test_utils/proc_table_replacement.h" ] + + deps = [ ":embedder_headers" ] + + public_configs = [ "//flutter:config" ] +} + # For using the embedder API as internal implementation detail of an # embedding. config("embedder_internal_library_config") { @@ -200,6 +208,33 @@ if (enable_unittests) { deps += [ "//flutter/testing:opengl" ] } } + + # Tests the build in FLUTTER_ENGINE_NO_PROTOTYPES mode. + executable("embedder_proctable_unittests") { + testonly = true + + configs += [ + ":embedder_gpu_configuration_config", + "//flutter:export_dynamic_symbols", + ] + + sources = [ "tests/embedder_unittests_proctable.cc" ] + + defines = [ "FLUTTER_ENGINE_NO_PROTOTYPES" ] + + deps = [ + ":embedder", + ":embedder_gpu_configuration", + ":fixtures", + "//flutter/testing", + + #"//flutter/testing:dart", + #"//flutter/testing:skia", + #"//flutter/third_party/tonic", + #"//third_party/dart/runtime/bin:elf_loader", + #"//third_party/skia", + ] + } } shared_library("flutter_engine_library") { diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 4f2aec0a03ef1..ae9849a5a328a 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -50,7 +50,7 @@ extern const intptr_t kPlatformStrongDillSize; #include "flutter/shell/platform/embedder/embedder_engine.h" #include "flutter/shell/platform/embedder/embedder_platform_message_response.h" #include "flutter/shell/platform/embedder/embedder_render_target.h" -#include "flutter/shell/platform/embedder/embedder_safe_access.h" +#include "flutter/shell/platform/embedder/embedder_struct_macros.h" #include "flutter/shell/platform/embedder/embedder_task_runner.h" #include "flutter/shell/platform/embedder/embedder_thread_host.h" #include "flutter/shell/platform/embedder/platform_view_embedder.h" @@ -2048,3 +2048,57 @@ FlutterEngineResult FlutterEngineNotifyDisplayUpdate( "Invalid FlutterEngineDisplaysUpdateType type specified."); } } + +FlutterEngineResult FlutterEngineGetProcAddresses( + FlutterEngineProcTable* table) { + if (!table) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, "Null table specified."); + } +#define SET_PROC(member, function) \ + if (STRUCT_HAS_MEMBER(table, member)) { \ + table->member = &function; \ + } + + SET_PROC(CreateAOTData, FlutterEngineCreateAOTData); + SET_PROC(CollectAOTData, FlutterEngineCollectAOTData); + SET_PROC(Run, FlutterEngineRun); + SET_PROC(Shutdown, FlutterEngineShutdown); + SET_PROC(Initialize, FlutterEngineInitialize); + SET_PROC(Deinitialize, FlutterEngineDeinitialize); + SET_PROC(RunInitialized, FlutterEngineRunInitialized); + SET_PROC(SendWindowMetricsEvent, FlutterEngineSendWindowMetricsEvent); + SET_PROC(SendPointerEvent, FlutterEngineSendPointerEvent); + SET_PROC(SendPlatformMessage, FlutterEngineSendPlatformMessage); + SET_PROC(PlatformMessageCreateResponseHandle, + FlutterPlatformMessageCreateResponseHandle); + SET_PROC(PlatformMessageReleaseResponseHandle, + FlutterPlatformMessageReleaseResponseHandle); + SET_PROC(SendPlatformMessageResponse, + FlutterEngineSendPlatformMessageResponse); + SET_PROC(RegisterExternalTexture, FlutterEngineRegisterExternalTexture); + SET_PROC(UnregisterExternalTexture, FlutterEngineUnregisterExternalTexture); + SET_PROC(MarkExternalTextureFrameAvailable, + FlutterEngineMarkExternalTextureFrameAvailable); + SET_PROC(UpdateSemanticsEnabled, FlutterEngineUpdateSemanticsEnabled); + SET_PROC(UpdateAccessibilityFeatures, + FlutterEngineUpdateAccessibilityFeatures); + SET_PROC(DispatchSemanticsAction, FlutterEngineDispatchSemanticsAction); + SET_PROC(OnVsync, FlutterEngineOnVsync); + SET_PROC(ReloadSystemFonts, FlutterEngineReloadSystemFonts); + SET_PROC(TraceEventDurationBegin, FlutterEngineTraceEventDurationBegin); + SET_PROC(TraceEventDurationEnd, FlutterEngineTraceEventDurationEnd); + SET_PROC(TraceEventInstant, FlutterEngineTraceEventInstant); + SET_PROC(PostRenderThreadTask, FlutterEnginePostRenderThreadTask); + SET_PROC(GetCurrentTime, FlutterEngineGetCurrentTime); + SET_PROC(RunTask, FlutterEngineRunTask); + SET_PROC(UpdateLocales, FlutterEngineUpdateLocales); + SET_PROC(RunsAOTCompiledDartCode, FlutterEngineRunsAOTCompiledDartCode); + SET_PROC(PostDartObject, FlutterEnginePostDartObject); + SET_PROC(NotifyLowMemoryWarning, FlutterEngineNotifyLowMemoryWarning); + SET_PROC(PostCallbackOnAllNativeThreads, + FlutterEnginePostCallbackOnAllNativeThreads); + SET_PROC(NotifyDisplayUpdate, FlutterEngineNotifyDisplayUpdate); +#undef SET_PROC + + return kSuccess; +} diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index f2cf40f914b73..f98f848e967b3 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1001,22 +1001,6 @@ typedef enum { kFlutterEngineDisplaysUpdateTypeCount, } FlutterEngineDisplaysUpdateType; -//------------------------------------------------------------------------------ -/// @brief Posts updates corresponding to display changes to a running engine -/// instance. -/// -/// @param[in] update_type The type of update pushed to the engine. -/// @param[in] displays The displays affected by this update. -/// @param[in] display_count Size of the displays array, must be at least 1. -/// -/// @return the result of the call made to the engine. -/// -FlutterEngineResult FlutterEngineNotifyDisplayUpdate( - FLUTTER_API_SYMBOL(FlutterEngine) engine, - FlutterEngineDisplaysUpdateType update_type, - const FlutterEngineDisplay* displays, - size_t display_count); - typedef int64_t FlutterEngineDartPort; typedef enum { @@ -1134,38 +1118,6 @@ typedef struct { /// FlutterEngine instance in AOT mode. typedef struct _FlutterEngineAOTData* FlutterEngineAOTData; -//------------------------------------------------------------------------------ -/// @brief Creates the necessary data structures to launch a Flutter Dart -/// application in AOT mode. The data may only be collected after -/// all FlutterEngine instances launched using this data have been -/// terminated. -/// -/// @param[in] source The source of the AOT data. -/// @param[out] data_out The AOT data on success. Unchanged on failure. -/// -/// @return Returns if the AOT data could be successfully resolved. -/// -FLUTTER_EXPORT -FlutterEngineResult FlutterEngineCreateAOTData( - const FlutterEngineAOTDataSource* source, - FlutterEngineAOTData* data_out); - -//------------------------------------------------------------------------------ -/// @brief Collects the AOT data. -/// -/// @warning The embedder must ensure that this call is made only after all -/// FlutterEngine instances launched using this data have been -/// terminated, and that all of those instances were launched with -/// the FlutterProjectArgs::shutdown_dart_vm_when_done flag set to -/// true. -/// -/// @param[in] data The data to collect. -/// -/// @return Returns if the AOT data was successfully collected. -/// -FLUTTER_EXPORT -FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data); - typedef struct { /// The size of this struct. Must be sizeof(FlutterProjectArgs). size_t struct_size; @@ -1387,6 +1339,40 @@ typedef struct { } FlutterProjectArgs; +#ifndef FLUTTER_ENGINE_NO_PROTOTYPES + +//------------------------------------------------------------------------------ +/// @brief Creates the necessary data structures to launch a Flutter Dart +/// application in AOT mode. The data may only be collected after +/// all FlutterEngine instances launched using this data have been +/// terminated. +/// +/// @param[in] source The source of the AOT data. +/// @param[out] data_out The AOT data on success. Unchanged on failure. +/// +/// @return Returns if the AOT data could be successfully resolved. +/// +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineCreateAOTData( + const FlutterEngineAOTDataSource* source, + FlutterEngineAOTData* data_out); + +//------------------------------------------------------------------------------ +/// @brief Collects the AOT data. +/// +/// @warning The embedder must ensure that this call is made only after all +/// FlutterEngine instances launched using this data have been +/// terminated, and that all of those instances were launched with +/// the FlutterProjectArgs::shutdown_dart_vm_when_done flag set to +/// true. +/// +/// @param[in] data The data to collect. +/// +/// @return Returns if the AOT data was successfully collected. +/// +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data); + //------------------------------------------------------------------------------ /// @brief Initialize and run a Flutter engine instance and return a handle /// to it. This is a convenience method for the pair of calls to @@ -1970,6 +1956,191 @@ FlutterEngineResult FlutterEnginePostCallbackOnAllNativeThreads( FlutterNativeThreadCallback callback, void* user_data); +//------------------------------------------------------------------------------ +/// @brief Posts updates corresponding to display changes to a running engine +/// instance. +/// +/// @param[in] update_type The type of update pushed to the engine. +/// @param[in] displays The displays affected by this update. +/// @param[in] display_count Size of the displays array, must be at least 1. +/// +/// @return the result of the call made to the engine. +/// +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineNotifyDisplayUpdate( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterEngineDisplaysUpdateType update_type, + const FlutterEngineDisplay* displays, + size_t display_count); + +#endif // !FLUTTER_ENGINE_NO_PROTOTYPES + +// Typedefs for the function pointers in FlutterEngineProcTable. +typedef FlutterEngineResult (*FlutterEngineCreateAOTDataFnPtr)( + const FlutterEngineAOTDataSource* source, + FlutterEngineAOTData* data_out); +typedef FlutterEngineResult (*FlutterEngineCollectAOTDataFnPtr)( + FlutterEngineAOTData data); +typedef FlutterEngineResult (*FlutterEngineRunFnPtr)( + size_t version, + const FlutterRendererConfig* config, + const FlutterProjectArgs* args, + void* user_data, + FLUTTER_API_SYMBOL(FlutterEngine) * engine_out); +typedef FlutterEngineResult (*FlutterEngineShutdownFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine); +typedef FlutterEngineResult (*FlutterEngineInitializeFnPtr)( + size_t version, + const FlutterRendererConfig* config, + const FlutterProjectArgs* args, + void* user_data, + FLUTTER_API_SYMBOL(FlutterEngine) * engine_out); +typedef FlutterEngineResult (*FlutterEngineDeinitializeFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine); +typedef FlutterEngineResult (*FlutterEngineRunInitializedFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine); +typedef FlutterEngineResult (*FlutterEngineSendWindowMetricsEventFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterWindowMetricsEvent* event); +typedef FlutterEngineResult (*FlutterEngineSendPointerEventFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterPointerEvent* events, + size_t events_count); +typedef FlutterEngineResult (*FlutterEngineSendPlatformMessageFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterPlatformMessage* message); +typedef FlutterEngineResult ( + *FlutterEnginePlatformMessageCreateResponseHandleFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterDataCallback data_callback, + void* user_data, + FlutterPlatformMessageResponseHandle** response_out); +typedef FlutterEngineResult ( + *FlutterEnginePlatformMessageReleaseResponseHandleFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterPlatformMessageResponseHandle* response); +typedef FlutterEngineResult (*FlutterEngineSendPlatformMessageResponseFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterPlatformMessageResponseHandle* handle, + const uint8_t* data, + size_t data_length); +typedef FlutterEngineResult (*FlutterEngineRegisterExternalTextureFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t texture_identifier); +typedef FlutterEngineResult (*FlutterEngineUnregisterExternalTextureFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t texture_identifier); +typedef FlutterEngineResult ( + *FlutterEngineMarkExternalTextureFrameAvailableFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + int64_t texture_identifier); +typedef FlutterEngineResult (*FlutterEngineUpdateSemanticsEnabledFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + bool enabled); +typedef FlutterEngineResult (*FlutterEngineUpdateAccessibilityFeaturesFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterAccessibilityFeature features); +typedef FlutterEngineResult (*FlutterEngineDispatchSemanticsActionFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + uint64_t id, + FlutterSemanticsAction action, + const uint8_t* data, + size_t data_length); +typedef FlutterEngineResult (*FlutterEngineOnVsyncFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + intptr_t baton, + uint64_t frame_start_time_nanos, + uint64_t frame_target_time_nanos); +typedef FlutterEngineResult (*FlutterEngineReloadSystemFontsFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine); +typedef void (*FlutterEngineTraceEventDurationBeginFnPtr)(const char* name); +typedef void (*FlutterEngineTraceEventDurationEndFnPtr)(const char* name); +typedef void (*FlutterEngineTraceEventInstantFnPtr)(const char* name); +typedef FlutterEngineResult (*FlutterEnginePostRenderThreadTaskFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + VoidCallback callback, + void* callback_data); +typedef uint64_t (*FlutterEngineGetCurrentTimeFnPtr)(); +typedef FlutterEngineResult (*FlutterEngineRunTaskFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterTask* task); +typedef FlutterEngineResult (*FlutterEngineUpdateLocalesFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterLocale** locales, + size_t locales_count); +typedef bool (*FlutterEngineRunsAOTCompiledDartCodeFnPtr)(void); +typedef FlutterEngineResult (*FlutterEnginePostDartObjectFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterEngineDartPort port, + const FlutterEngineDartObject* object); +typedef FlutterEngineResult (*FlutterEngineNotifyLowMemoryWarningFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine); +typedef FlutterEngineResult (*FlutterEnginePostCallbackOnAllNativeThreadsFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterNativeThreadCallback callback, + void* user_data); +typedef FlutterEngineResult (*FlutterEngineNotifyDisplayUpdateFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FlutterEngineDisplaysUpdateType update_type, + const FlutterEngineDisplay* displays, + size_t display_count); + +/// Function-pointer-based versions of the APIs above. +typedef struct { + /// The size of this struct. Must be sizeof(FlutterEngineProcs). + size_t struct_size; + + FlutterEngineCreateAOTDataFnPtr CreateAOTData; + FlutterEngineCollectAOTDataFnPtr CollectAOTData; + FlutterEngineRunFnPtr Run; + FlutterEngineShutdownFnPtr Shutdown; + FlutterEngineInitializeFnPtr Initialize; + FlutterEngineDeinitializeFnPtr Deinitialize; + FlutterEngineRunInitializedFnPtr RunInitialized; + FlutterEngineSendWindowMetricsEventFnPtr SendWindowMetricsEvent; + FlutterEngineSendPointerEventFnPtr SendPointerEvent; + FlutterEngineSendPlatformMessageFnPtr SendPlatformMessage; + FlutterEnginePlatformMessageCreateResponseHandleFnPtr + PlatformMessageCreateResponseHandle; + FlutterEnginePlatformMessageReleaseResponseHandleFnPtr + PlatformMessageReleaseResponseHandle; + FlutterEngineSendPlatformMessageResponseFnPtr SendPlatformMessageResponse; + FlutterEngineRegisterExternalTextureFnPtr RegisterExternalTexture; + FlutterEngineUnregisterExternalTextureFnPtr UnregisterExternalTexture; + FlutterEngineMarkExternalTextureFrameAvailableFnPtr + MarkExternalTextureFrameAvailable; + FlutterEngineUpdateSemanticsEnabledFnPtr UpdateSemanticsEnabled; + FlutterEngineUpdateAccessibilityFeaturesFnPtr UpdateAccessibilityFeatures; + FlutterEngineDispatchSemanticsActionFnPtr DispatchSemanticsAction; + FlutterEngineOnVsyncFnPtr OnVsync; + FlutterEngineReloadSystemFontsFnPtr ReloadSystemFonts; + FlutterEngineTraceEventDurationBeginFnPtr TraceEventDurationBegin; + FlutterEngineTraceEventDurationEndFnPtr TraceEventDurationEnd; + FlutterEngineTraceEventInstantFnPtr TraceEventInstant; + FlutterEnginePostRenderThreadTaskFnPtr PostRenderThreadTask; + FlutterEngineGetCurrentTimeFnPtr GetCurrentTime; + FlutterEngineRunTaskFnPtr RunTask; + FlutterEngineUpdateLocalesFnPtr UpdateLocales; + FlutterEngineRunsAOTCompiledDartCodeFnPtr RunsAOTCompiledDartCode; + FlutterEnginePostDartObjectFnPtr PostDartObject; + FlutterEngineNotifyLowMemoryWarningFnPtr NotifyLowMemoryWarning; + FlutterEnginePostCallbackOnAllNativeThreadsFnPtr + PostCallbackOnAllNativeThreads; + FlutterEngineNotifyDisplayUpdateFnPtr NotifyDisplayUpdate; +} FlutterEngineProcTable; + +//------------------------------------------------------------------------------ +/// @brief Gets the table of engine function pointers. +/// +/// @param[out] table The table to fill with pointers. This should be +/// zero-initialized, except for struct_size. +/// +/// @return Returns whether the table was successfully populated. +/// +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineGetProcAddresses( + FlutterEngineProcTable* table); + #if defined(__cplusplus) } // extern "C" #endif diff --git a/shell/platform/embedder/embedder_safe_access.h b/shell/platform/embedder/embedder_struct_macros.h similarity index 63% rename from shell/platform/embedder/embedder_safe_access.h rename to shell/platform/embedder/embedder_struct_macros.h index e9673a04a75ee..8bd3097951286 100644 --- a/shell/platform/embedder/embedder_safe_access.h +++ b/shell/platform/embedder/embedder_struct_macros.h @@ -7,21 +7,25 @@ #include -#define SAFE_ACCESS(pointer, member, default_value) \ - ([=]() { \ - if (offsetof(std::remove_pointer::type, member) + \ - sizeof(pointer->member) <= \ - pointer->struct_size) { \ - return pointer->member; \ - } \ - return static_castmember)>((default_value)); \ +// Checks if the given struct contains a member, whether set or not. +#define STRUCT_HAS_MEMBER(pointer, member) \ + ((offsetof(std::remove_pointer::type, member) + \ + sizeof(pointer->member) <= \ + pointer->struct_size)) + +#define SAFE_ACCESS(pointer, member, default_value) \ + ([=]() { \ + if (STRUCT_HAS_MEMBER(pointer, member)) { \ + return pointer->member; \ + } \ + return static_castmember)>((default_value)); \ })() -/// Checks if the member exists. +/// Checks if the member exists and is non-null. #define SAFE_EXISTS(pointer, member) \ (SAFE_ACCESS(pointer, member, nullptr) != nullptr) -/// Checks if exactly one of member1 or member2 exists. +/// Checks if exactly one of member1 or member2 exists and is non-null. #define SAFE_EXISTS_ONE_OF(pointer, member1, member2) \ (SAFE_EXISTS(pointer, member1) != SAFE_EXISTS(pointer, member2)) diff --git a/shell/platform/embedder/embedder_thread_host.cc b/shell/platform/embedder/embedder_thread_host.cc index 83860eb635d56..15dd91d009b50 100644 --- a/shell/platform/embedder/embedder_thread_host.cc +++ b/shell/platform/embedder/embedder_thread_host.cc @@ -9,7 +9,7 @@ #include #include "flutter/fml/message_loop.h" -#include "flutter/shell/platform/embedder/embedder_safe_access.h" +#include "flutter/shell/platform/embedder/embedder_struct_macros.h" namespace flutter { diff --git a/shell/platform/embedder/test_utils/proc_table_replacement.h b/shell/platform/embedder/test_utils/proc_table_replacement.h new file mode 100644 index 0000000000000..f04299dcbed7f --- /dev/null +++ b/shell/platform/embedder/test_utils/proc_table_replacement.h @@ -0,0 +1,23 @@ +// Copyright 2013 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.h" + +// Wraps capturing lambas with non-capturing version that can be assigned to +// FlutterEngineProcTable entries (by using statics) to facilitate mocking in +// tests of code built on top of the embedder API. +// +// This should *ONLY* be used in unit tests as it is leaky by design. +// +// |proc| should be the name of an entry in FlutterEngineProcTable, such as +// "initialize". |mock_impl| should be a lamba that replaces its implementation, +// taking the same arguments and returning the same type. +#define MOCK_ENGINE_PROC(proc, mock_impl) \ + ([&]() { \ + static std::function< \ + std::remove_pointer_t> \ + closure = mock_impl; \ + static auto non_capturing = [](auto... args) { return closure(args...); }; \ + return non_capturing; \ + })() diff --git a/shell/platform/embedder/tests/embedder_unittests_proctable.cc b/shell/platform/embedder/tests/embedder_unittests_proctable.cc new file mode 100644 index 0000000000000..dd1462c8f3d26 --- /dev/null +++ b/shell/platform/embedder/tests/embedder_unittests_proctable.cc @@ -0,0 +1,62 @@ +// Copyright 2013 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.h" + +#include + +#include "flutter/testing/testing.h" + +#ifdef _WIN32 +// winbase.h defines GetCurrentTime as a macro. +#undef GetCurrentTime +#endif + +namespace flutter { +namespace testing { + +// Verifies that the proc table is fully populated. +TEST(EmbedderProcTable, AllPointersProvided) { + FlutterEngineProcTable procs = {}; + procs.struct_size = sizeof(FlutterEngineProcTable); + ASSERT_EQ(FlutterEngineGetProcAddresses(&procs), kSuccess); + + void (**proc)() = reinterpret_cast(&procs.CreateAOTData); + const uintptr_t end_address = + reinterpret_cast(&procs) + procs.struct_size; + while (reinterpret_cast(proc) < end_address) { + EXPECT_NE(*proc, nullptr); + ++proc; + } +} + +// Ensures that there are no duplicate pointers in the proc table, to catch +// copy/paste mistakes when adding a new entry to FlutterEngineGetProcAddresses. +TEST(EmbedderProcTable, NoDuplicatePointers) { + FlutterEngineProcTable procs = {}; + procs.struct_size = sizeof(FlutterEngineProcTable); + ASSERT_EQ(FlutterEngineGetProcAddresses(&procs), kSuccess); + + void (**proc)() = reinterpret_cast(&procs.CreateAOTData); + const uintptr_t end_address = + reinterpret_cast(&procs) + procs.struct_size; + std::set seen_procs; + while (reinterpret_cast(proc) < end_address) { + auto result = seen_procs.insert(*proc); + EXPECT_TRUE(result.second); + ++proc; + } +} + +// Spot-checks that calling one of the function pointers works. +TEST(EmbedderProcTable, CallProc) { + FlutterEngineProcTable procs = {}; + procs.struct_size = sizeof(FlutterEngineProcTable); + ASSERT_EQ(FlutterEngineGetProcAddresses(&procs), kSuccess); + + EXPECT_NE(procs.GetCurrentTime(), 0ULL); +} + +} // namespace testing +} // namespace flutter diff --git a/testing/run_tests.py b/testing/run_tests.py index cfcedd74f7816..06b8256d0bc8a 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -113,6 +113,7 @@ def RunCCTests(build_dir, filter): # https://github.com/flutter/flutter/issues/36294 if not IsWindows(): RunEngineExecutable(build_dir, 'embedder_unittests', filter, shuffle_flags) + RunEngineExecutable(build_dir, 'embedder_proctable_unittests', filter, shuffle_flags) else: RunEngineExecutable(build_dir, 'flutter_windows_unittests', filter, shuffle_flags)