forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
shell.h
571 lines (491 loc) · 24.9 KB
/
shell.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
// 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.
#ifndef SHELL_COMMON_SHELL_H_
#define SHELL_COMMON_SHELL_H_
#include <functional>
#include <string_view>
#include <unordered_map>
#include "flutter/common/settings.h"
#include "flutter/common/task_runners.h"
#include "flutter/flow/texture.h"
#include "flutter/fml/closure.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/ref_ptr.h"
#include "flutter/fml/memory/thread_checker.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/fml/status.h"
#include "flutter/fml/synchronization/sync_switch.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/thread.h"
#include "flutter/lib/ui/semantics/custom_accessibility_action.h"
#include "flutter/lib/ui/semantics/semantics_node.h"
#include "flutter/lib/ui/window/platform_message.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/runtime/service_protocol.h"
#include "flutter/shell/common/animator.h"
#include "flutter/shell/common/engine.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/shell_io_manager.h"
#include "flutter/shell/common/surface.h"
namespace flutter {
/// Error exit codes for the Dart isolate.
enum class DartErrorCode {
/// No error has occurred.
NoError = 0,
/// The Dart error code for an API error.
ApiError = 253,
/// The Dart error code for a compilation error.
CompilationError = 254,
/// The Dart error code for an unkonwn error.
UnknownError = 255
};
//------------------------------------------------------------------------------
/// Perhaps the single most important class in the Flutter engine repository.
/// When embedders create a Flutter application, they are referring to the
/// creation of an instance of a shell. Creation and destruction of the shell is
/// synchronous and the embedder only holds a unique pointer to the shell. The
/// shell does not create the threads its primary components run on. Instead, it
/// is the embedder's responsibility to create threads and give the shell task
/// runners for those threads. Due to deterministic destruction of the shell,
/// the embedder can terminate all threads immediately after collecting the
/// shell. The shell must be created and destroyed on the same thread, but,
/// different shells (i.e. a separate instances of a Flutter application) may be
/// run on different threads simultaneously. The task runners themselves do not
/// have to be unique. If all task runner references given to the shell during
/// shell creation point to the same task runner, the Flutter application is
/// effectively single threaded.
///
/// The shell is the central nervous system of the Flutter application. None of
/// the shell components are thread safe and must be created, accessed and
/// destroyed on the same thread. To interact with one another, the various
/// components delegate to the shell for communication. Instead of using back
/// pointers to the shell, a delegation pattern is used by all components that
/// want to communicate with one another. Because of this, the shell implements
/// the delegate interface for all these components.
///
/// All shell methods accessed by the embedder may only be called on the
/// platform task runner. In case the embedder wants to directly access a shell
/// subcomponent, it is the embedder's responsibility to acquire a weak pointer
/// to that component and post a task to the task runner used by the component
/// to access its methods. The shell must also be destroyed on the platform
/// task runner.
///
/// There is no explicit API to bootstrap and shutdown the Dart VM. The first
/// instance of the shell in the process bootstraps the Dart VM and the
/// destruction of the last shell instance destroys the same. Since different
/// shells may be created and destroyed on different threads. VM bootstrap may
/// happen on one thread but its collection on another. This behavior is thread
/// safe.
///
class Shell final : public PlatformView::Delegate,
public Animator::Delegate,
public Engine::Delegate,
public Rasterizer::Delegate,
public ServiceProtocol::Handler {
public:
template <class T>
using CreateCallback = std::function<std::unique_ptr<T>(Shell&)>;
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// If this is the first instance of a shell in the process, this
/// call also bootstraps the Dart VM.
///
/// @param[in] task_runners The task runners
/// @param[in] settings The settings
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
static std::unique_ptr<Shell> Create(
TaskRunners task_runners,
Settings settings,
const CreateCallback<PlatformView>& on_create_platform_view,
const CreateCallback<Rasterizer>& on_create_rasterizer);
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// Unlike the simpler variant of this factory method, this method
/// allows for specification of window data. If this is the first
/// instance of a shell in the process, this call also bootstraps
/// the Dart VM.
///
/// @param[in] task_runners The task runners
/// @param[in] window_data The default data for setting up
/// ui.Window that attached to this
/// intance.
/// @param[in] settings The settings
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
static std::unique_ptr<Shell> Create(
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
CreateCallback<PlatformView> on_create_platform_view,
CreateCallback<Rasterizer> on_create_rasterizer);
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// Unlike the simpler variant of this factory method, this method
/// allows for the specification of an isolate snapshot that
/// cannot be adequately described in the settings. This call also
/// requires the specification of a running VM instance.
///
/// @param[in] task_runners The task runners
/// @param[in] window_data The default data for setting up
/// ui.Window that attached to this
/// intance.
/// @param[in] settings The settings
/// @param[in] isolate_snapshot A custom isolate snapshot. Takes
/// precedence over any snapshots
/// specified in the settings.
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
/// @param[in] vm A running VM instance.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
static std::unique_ptr<Shell> Create(
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
const CreateCallback<PlatformView>& on_create_platform_view,
const CreateCallback<Rasterizer>& on_create_rasterizer,
DartVMRef vm);
//----------------------------------------------------------------------------
/// @brief Destroys the shell. This is a synchronous operation and
/// synchronous barrier blocks are introduced on the various
/// threads to ensure shutdown of all shell sub-components before
/// this method returns.
///
~Shell();
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration.
///
void RunEngine(RunConfiguration run_configuration);
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration. The
/// result_callback will be called with the status of the
/// operation.
///
void RunEngine(RunConfiguration run_configuration,
const std::function<void(Engine::RunStatus)>& result_callback);
//------------------------------------------------------------------------------
/// @return The settings used to launch this shell.
///
const Settings& GetSettings() const;
//------------------------------------------------------------------------------
/// @brief If callers wish to interact directly with any shell
/// subcomponents, they must (on the platform thread) obtain a
/// task runner that the component is designed to run on and a
/// weak pointer to that component. They may then post a task to
/// that task runner, do the validity check on that task runner
/// before performing any operation on that component. This
/// accessor allows callers to access the task runners for this
/// shell.
///
/// @return The task runners current in use by the shell.
///
const TaskRunners& GetTaskRunners() const;
//----------------------------------------------------------------------------
/// @brief Rasterizers may only be accessed on the GPU task runner.
///
/// @return A weak pointer to the rasterizer.
///
fml::WeakPtr<Rasterizer> GetRasterizer() const;
//------------------------------------------------------------------------------
/// @brief Engines may only be accessed on the UI thread. This method is
/// deprecated, and implementers should instead use other API
/// available on the Shell or the PlatformView.
///
/// @return A weak pointer to the engine.
///
fml::WeakPtr<Engine> GetEngine();
//----------------------------------------------------------------------------
/// @brief Platform views may only be accessed on the platform task
/// runner.
///
/// @return A weak pointer to the platform view.
///
fml::WeakPtr<PlatformView> GetPlatformView();
// Embedders should call this under low memory conditions to free up
// internal caches used.
//
// This method posts a task to the GPU threads to signal the Rasterizer to
// free resources.
//----------------------------------------------------------------------------
/// @brief Used by embedders to notify that there is a low memory
/// warning. The shell will attempt to purge caches. Current, only
/// the rasterizer cache is purged.
void NotifyLowMemoryWarning() const;
//----------------------------------------------------------------------------
/// @brief Used by embedders to check if all shell subcomponents are
/// initialized. It is the embedder's responsibility to make this
/// call before accessing any other shell method. A shell that is
/// not setup must be discarded and another one created with
/// updated settings.
///
/// @return Returns if the shell has been setup. Once set up, this does
/// not change for the life-cycle of the shell.
///
bool IsSetup() const;
//----------------------------------------------------------------------------
/// @brief Captures a screenshot and optionally Base64 encodes the data
/// of the last layer tree rendered by the rasterizer in this
/// shell.
///
/// @param[in] type The type of screenshot to capture.
/// @param[in] base64_encode If the screenshot data should be base64
/// encoded.
///
/// @return The screenshot result.
///
Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type,
bool base64_encode);
//----------------------------------------------------------------------------
/// @brief Pauses the calling thread until the first frame is presented.
///
/// @return 'kOk' when the first frame has been presented before the timeout
/// successfully, 'kFailedPrecondition' if called from the GPU or UI
/// thread, 'kDeadlineExceeded' if there is a timeout.
///
fml::Status WaitForFirstFrame(fml::TimeDelta timeout);
//----------------------------------------------------------------------------
/// @brief Used by embedders to reload the system fonts in
/// FontCollection.
/// It also clears the cached font families and send system
/// channel message to framework to rebuild affected widgets.
///
/// @return Returns if shell reloads system fonts successfully.
///
bool ReloadSystemFonts();
//----------------------------------------------------------------------------
/// @brief Used by embedders to get the last error from the Dart UI
/// Isolate, if one exists.
///
/// @return Returns the last error code from the UI Isolate.
///
std::optional<DartErrorCode> GetUIIsolateLastError() const;
//----------------------------------------------------------------------------
/// @brief Used by embedders to check if the Engine is running and has
/// any live ports remaining. For example, the Flutter tester uses
/// this method to check whether it should continue to wait for
/// a running test or not.
///
/// @return Returns if the shell has an engine and the engine has any live
/// Dart ports.
///
bool EngineHasLivePorts() const;
//----------------------------------------------------------------------------
/// @brief Accessor for the disable GPU SyncSwitch
std::shared_ptr<fml::SyncSwitch> GetIsGpuDisabledSyncSwitch() const;
private:
using ServiceProtocolHandler =
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
rapidjson::Document&)>;
const TaskRunners task_runners_;
const Settings settings_;
DartVMRef vm_;
std::unique_ptr<PlatformView> platform_view_; // on platform task runner
std::unique_ptr<Engine> engine_; // on UI task runner
std::unique_ptr<Rasterizer> rasterizer_; // on GPU task runner
std::unique_ptr<ShellIOManager> io_manager_; // on IO task runner
std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch_;
fml::WeakPtr<Engine> weak_engine_; // to be shared across threads
fml::WeakPtr<Rasterizer> weak_rasterizer_; // to be shared across threads
fml::WeakPtr<PlatformView>
weak_platform_view_; // to be shared across threads
std::unordered_map<std::string_view, // method
std::pair<fml::RefPtr<fml::TaskRunner>,
ServiceProtocolHandler> // task-runner/function
// pair
>
service_protocol_handlers_;
bool is_setup_ = false;
uint64_t next_pointer_flow_id_ = 0;
bool first_frame_rasterized_ = false;
std::atomic<bool> waiting_for_first_frame_ = true;
std::mutex waiting_for_first_frame_mutex_;
std::condition_variable waiting_for_first_frame_condition_;
// Written in the UI thread and read from the GPU thread. Hence make it
// atomic.
std::atomic<bool> needs_report_timings_{false};
// Whether there's a task scheduled to report the timings to Dart through
// ui.Window.onReportTimings.
bool frame_timings_report_scheduled_ = false;
// Vector of FrameTiming::kCount * n timestamps for n frames whose timings
// have not been reported yet. Vector of ints instead of FrameTiming is stored
// here for easier conversions to Dart objects.
std::vector<int64_t> unreported_timings_;
// A cache of `Engine::GetDisplayRefreshRate` (only callable in the UI thread)
// so we can access it from `Rasterizer` (in the GPU thread).
//
// The atomic is for extra thread safety as this is written in the UI thread
// and read from the GPU thread.
std::atomic<float> display_refresh_rate_ = 0.0f;
// How many frames have been timed since last report.
size_t UnreportedFramesCount() const;
Shell(DartVMRef vm, TaskRunners task_runners, Settings settings);
static std::unique_ptr<Shell> CreateShellOnPlatformThread(
DartVMRef vm,
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer);
bool Setup(std::unique_ptr<PlatformView> platform_view,
std::unique_ptr<Engine> engine,
std::unique_ptr<Rasterizer> rasterizer,
std::unique_ptr<ShellIOManager> io_manager);
DartVM* GetDartVM();
void ReportTimings();
// |PlatformView::Delegate|
void OnPlatformViewCreated(std::unique_ptr<Surface> surface) override;
// |PlatformView::Delegate|
void OnPlatformViewDestroyed() override;
// |PlatformView::Delegate|
void OnPlatformViewSetViewportMetrics(
const ViewportMetrics& metrics) override;
// |PlatformView::Delegate|
void OnPlatformViewDispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) override;
// |PlatformView::Delegate|
void OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) override;
// |PlatformView::Delegate|
void OnPlatformViewDispatchSemanticsAction(
int32_t id,
SemanticsAction action,
std::vector<uint8_t> args) override;
// |PlatformView::Delegate|
void OnPlatformViewSetSemanticsEnabled(bool enabled) override;
// |shell:PlatformView::Delegate|
void OnPlatformViewSetAccessibilityFeatures(int32_t flags) override;
// |PlatformView::Delegate|
void OnPlatformViewRegisterTexture(
std::shared_ptr<flutter::Texture> texture) override;
// |PlatformView::Delegate|
void OnPlatformViewUnregisterTexture(int64_t texture_id) override;
// |PlatformView::Delegate|
void OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) override;
// |PlatformView::Delegate|
void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) override;
// |Animator::Delegate|
void OnAnimatorBeginFrame(fml::TimePoint frame_time) override;
// |Animator::Delegate|
void OnAnimatorNotifyIdle(int64_t deadline) override;
// |Animator::Delegate|
void OnAnimatorDraw(
fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) override;
// |Animator::Delegate|
void OnAnimatorDrawLastLayerTree() override;
// |Engine::Delegate|
void OnEngineUpdateSemantics(
SemanticsNodeUpdates update,
CustomAccessibilityActionUpdates actions) override;
// |Engine::Delegate|
void OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) override;
void HandleEngineSkiaMessage(fml::RefPtr<PlatformMessage> message);
// |Engine::Delegate|
void OnPreEngineRestart() override;
// |Engine::Delegate|
void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) override;
// |Engine::Delegate|
void SetNeedsReportTimings(bool value) override;
// |Rasterizer::Delegate|
void OnFrameRasterized(const FrameTiming&) override;
// |Rasterizer::Delegate|
fml::Milliseconds GetFrameBudget() override;
// |ServiceProtocol::Handler|
fml::RefPtr<fml::TaskRunner> GetServiceProtocolHandlerTaskRunner(
std::string_view method) const override;
// |ServiceProtocol::Handler|
bool HandleServiceProtocolMessage(
std::string_view method, // one if the extension names specified above.
const ServiceProtocolMap& params,
rapidjson::Document& response) override;
// |ServiceProtocol::Handler|
ServiceProtocol::Handler::Description GetServiceProtocolDescription()
const override;
// Service protocol handler
bool OnServiceProtocolScreenshot(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolScreenshotSKP(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolRunInView(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolFlushUIThreadTasks(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolSetAssetBundlePath(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolGetDisplayRefreshRate(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
fml::WeakPtrFactory<Shell> weak_factory_;
// For accessing the Shell via the GPU thread, necessary for various
// rasterizer callbacks.
std::unique_ptr<fml::WeakPtrFactory<Shell>> weak_factory_gpu_;
friend class testing::ShellTest;
FML_DISALLOW_COPY_AND_ASSIGN(Shell);
};
} // namespace flutter
#endif // SHELL_COMMON_SHELL_H_