forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dart_isolate.h
525 lines (468 loc) · 23.7 KB
/
dart_isolate.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
// 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 FLUTTER_RUNTIME_DART_ISOLATE_H_
#define FLUTTER_RUNTIME_DART_ISOLATE_H_
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <unordered_set>
#include "flutter/common/task_runners.h"
#include "flutter/fml/compiler_specific.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
#include "flutter/lib/ui/io_manager.h"
#include "flutter/lib/ui/snapshot_delegate.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "flutter/lib/ui/window/platform_configuration.h"
#include "flutter/runtime/dart_snapshot.h"
#include "flutter/runtime/isolate_configuration.h"
#include "third_party/dart/runtime/include/dart_api.h"
#include "third_party/tonic/dart_state.h"
namespace flutter {
class DartVM;
class DartIsolateGroupData;
class IsolateConfiguration;
//------------------------------------------------------------------------------
/// @brief Represents an instance of a live isolate. An isolate is a
/// separate Dart execution context. Different Dart isolates don't
/// share memory and can be scheduled concurrently by the Dart VM on
/// one of the Dart VM managed worker pool threads.
///
/// The entire lifecycle of a Dart isolate is controlled by the Dart
/// VM. Because of this, the engine never holds a strong pointer to
/// the Dart VM for extended periods of time. This allows the VM (or
/// the isolates themselves) to terminate Dart execution without
/// consulting the engine.
///
/// The isolate that the engine creates to act as the host for the
/// Flutter application code with UI bindings is called the root
/// isolate.
///
/// The root isolate is special in the following ways:
/// * The root isolate forms a new isolate group. Child isolates are
/// added to their parents groups. When the root isolate dies, all
/// isolates in its group are terminated.
/// * Only root isolates get UI bindings.
/// * Root isolates execute their code on engine managed threads.
/// All other isolates run their Dart code on Dart VM managed
/// thread pool workers that the engine has no control over.
/// * Since the engine does not know the thread on which non-root
/// isolates are run, the engine has no opportunity to get a
/// reference to non-root isolates. Such isolates can only be
/// terminated if they terminate themselves or their isolate group
/// is torn down.
///
class DartIsolate : public UIDartState {
public:
class Flags {
public:
Flags();
explicit Flags(const Dart_IsolateFlags* flags);
~Flags();
void SetNullSafetyEnabled(bool enabled);
void SetIsDontNeedSafe(bool value);
Dart_IsolateFlags Get() const;
private:
Dart_IsolateFlags flags_;
};
//----------------------------------------------------------------------------
/// @brief The engine represents all dart isolates as being in one of the
/// known phases. By invoking various methods on the Dart isolate,
/// the engine transition the Dart isolate from one phase to the
/// next. The Dart isolate will only move from one phase to the
/// next in the order specified in the `DartIsolate::Phase` enum.
/// That is, once the isolate has moved out of a particular phase,
/// it can never transition back to that phase in the future.
/// There is no error recovery mechanism and callers that find
/// their isolates in an undesirable phase must discard the
/// isolate and start over.
///
enum class Phase {
// NOLINTBEGIN(readability-identifier-naming)
//--------------------------------------------------------------------------
/// The initial phase of all Dart isolates. This is an internal phase and
/// callers can never get a reference to a Dart isolate in this phase.
///
Unknown,
//--------------------------------------------------------------------------
/// The Dart isolate has been created but none of the library tag or message
/// handers have been set yet. The is an internal phase and callers can
/// never get a reference to a Dart isolate in this phase.
///
Uninitialized,
//--------------------------------------------------------------------------
/// The Dart isolate has been fully initialized but none of the
/// libraries referenced by that isolate have been loaded yet. This is an
/// internal phase and callers can never get a reference to a Dart isolate
/// in this phase.
///
Initialized,
//--------------------------------------------------------------------------
/// The isolate has been fully initialized and is waiting for the caller to
/// associate isolate snapshots with the same. The isolate will only be
/// ready to execute Dart code once one of the `Prepare` calls are
/// successfully made.
///
LibrariesSetup,
//--------------------------------------------------------------------------
/// The isolate is fully ready to start running Dart code. Callers can
/// transition the isolate to the next state by calling the `Run` or
/// `RunFromLibrary` methods.
///
Ready,
//--------------------------------------------------------------------------
/// The isolate is currently running Dart code.
///
Running,
//--------------------------------------------------------------------------
/// The isolate is no longer running Dart code and is in the middle of being
/// collected. This is in internal phase and callers can never get a
/// reference to a Dart isolate in this phase.
///
Shutdown,
// NOLINTEND(readability-identifier-naming)
};
//----------------------------------------------------------------------------
/// @brief Creates an instance of a root isolate and returns a weak
/// pointer to the same. The isolate instance may only be used
/// safely on the engine thread on which it was created. In the
/// shell, this is the UI thread and task runner. Using the
/// isolate on any other thread is user error.
///
/// The isolate that the engine creates to act as the host for the
/// Flutter application code with UI bindings is called the root
/// isolate.
///
/// The root isolate is special in the following ways:
/// * The root isolate forms a new isolate group. Child isolates
/// are added to their parents groups. When the root isolate
/// dies, all isolates in its group are terminated.
/// * Only root isolates get UI bindings.
/// * Root isolates execute their code on engine managed threads.
/// All other isolates run their Dart code on Dart VM managed
/// thread pool workers that the engine has no control over.
/// * Since the engine does not know the thread on which non-root
/// isolates are run, the engine has no opportunity to get a
/// reference to non-root isolates. Such isolates can only be
/// terminated if they terminate themselves or their isolate
/// group is torn down.
///
/// @param[in] settings The settings used to create the
/// isolate.
/// @param[in] platform_configuration The platform configuration for
/// handling communication with the
/// framework.
/// @param[in] flags The Dart isolate flags for this
/// isolate instance.
/// @param[in] dart_entrypoint The name of the dart entrypoint
/// function to invoke.
/// @param[in] dart_entrypoint_library The name of the dart library
/// containing the entrypoint.
/// @param[in] dart_entrypoint_args Arguments passed as a List<String>
/// to Dart's entrypoint function.
/// @param[in] isolate_configuration The isolate configuration used to
/// configure the isolate before
/// invoking the entrypoint.
/// @param[in] root_isolate_create_callback A callback called after the root
/// isolate is created, _without_
/// isolate scope. This gives the
/// caller a chance to finish any
/// setup before running the Dart
/// program, and after any embedder
/// callbacks in the settings object.
/// @param[in] isolate_create_callback The isolate create callback. This
/// will be called when the before the
/// main Dart entrypoint is invoked in
/// the root isolate. The isolate is
/// already in the running state at
/// this point and an isolate scope is
/// current.
/// @param[in] isolate_shutdown_callback The isolate shutdown callback.
/// This will be called before the
/// isolate is about to transition
/// into the Shutdown phase. The
/// isolate is still running at this
/// point and an isolate scope is
/// current.
/// @param[in] context Engine-owned state which is
/// accessed by the root dart isolate.
/// @param[in] spawning_isolate The isolate that is spawning the
/// new isolate.
/// @return A weak pointer to the root Dart isolate. The caller must
/// ensure that the isolate is not referenced for long periods of
/// time as it prevents isolate collection when the isolate
/// terminates itself. The caller may also only use the isolate on
/// the thread on which the isolate was created.
///
static std::weak_ptr<DartIsolate> CreateRunningRootIsolate(
const Settings& settings,
const fml::RefPtr<const DartSnapshot>& isolate_snapshot,
std::unique_ptr<PlatformConfiguration> platform_configuration,
Flags flags,
const fml::closure& root_isolate_create_callback,
const fml::closure& isolate_create_callback,
const fml::closure& isolate_shutdown_callback,
std::optional<std::string> dart_entrypoint,
std::optional<std::string> dart_entrypoint_library,
const std::vector<std::string>& dart_entrypoint_args,
std::unique_ptr<IsolateConfiguration> isolate_configuration,
const UIDartState::Context& context,
const DartIsolate* spawning_isolate = nullptr);
// |UIDartState|
~DartIsolate() override;
//----------------------------------------------------------------------------
/// @brief The current phase of the isolate. The engine represents all
/// dart isolates as being in one of the known phases. By invoking
/// various methods on the Dart isolate, the engine transitions
/// the Dart isolate from one phase to the next. The Dart isolate
/// will only move from one phase to the next in the order
/// specified in the `DartIsolate::Phase` enum. That is, the once
/// the isolate has moved out of a particular phase, it can never
/// transition back to that phase in the future. There is no error
/// recovery mechanism and callers that find their isolates in an
/// undesirable phase must discard the isolate and start over.
///
/// @return The current isolate phase.
///
Phase GetPhase() const;
//----------------------------------------------------------------------------
/// @brief Returns the ID for an isolate which is used to query the
/// service protocol.
///
/// @return The service identifier for this isolate.
///
std::string GetServiceId();
//----------------------------------------------------------------------------
/// @brief Prepare the isolate for running for a precompiled code bundle.
/// The Dart VM must be configured for running precompiled code.
///
/// The isolate must already be in the `Phase::LibrariesSetup`
/// phase. After a successful call to this method, the isolate
/// will transition to the `Phase::Ready` phase.
///
/// @return Whether the isolate was prepared and the described phase
/// transition made.
///
[[nodiscard]] bool PrepareForRunningFromPrecompiledCode();
//----------------------------------------------------------------------------
/// @brief Prepare the isolate for running for a a list of kernel files.
///
/// The Dart VM must be configured for running from kernel
/// snapshots.
///
/// The isolate must already be in the `Phase::LibrariesSetup`
/// phase. This call can be made multiple times. After a series of
/// successful calls to this method, the caller can specify the
/// last kernel file mapping by specifying `last_piece` to `true`.
/// On success, the isolate will transition to the `Phase::Ready`
/// phase.
///
/// @param[in] kernel The kernel mapping.
/// @param[in] last_piece Indicates if this is the last kernel mapping
/// expected. After this point, the isolate will
/// attempt a transition to the `Phase::Ready` phase.
///
/// @return If the kernel mapping supplied was successfully used to
/// prepare the isolate.
///
[[nodiscard]] bool PrepareForRunningFromKernel(
const std::shared_ptr<const fml::Mapping>& kernel,
bool child_isolate,
bool last_piece);
//----------------------------------------------------------------------------
/// @brief Prepare the isolate for running for a a list of kernel files.
///
/// The Dart VM must be configured for running from kernel
/// snapshots.
///
/// The isolate must already be in the `Phase::LibrariesSetup`
/// phase. After a successful call to this method, the isolate
/// will transition to the `Phase::Ready` phase.
///
/// @param[in] kernels The kernels
///
/// @return If the kernel mappings supplied were successfully used to
/// prepare the isolate.
///
[[nodiscard]] bool PrepareForRunningFromKernels(
std::vector<std::shared_ptr<const fml::Mapping>> kernels);
//----------------------------------------------------------------------------
/// @brief Prepare the isolate for running for a a list of kernel files.
///
/// The Dart VM must be configured for running from kernel
/// snapshots.
///
/// The isolate must already be in the `Phase::LibrariesSetup`
/// phase. After a successful call to this method, the isolate
/// will transition to the `Phase::Ready` phase.
///
/// @param[in] kernels The kernels
///
/// @return If the kernel mappings supplied were successfully used to
/// prepare the isolate.
///
[[nodiscard]] bool PrepareForRunningFromKernels(
std::vector<std::unique_ptr<const fml::Mapping>> kernels);
//----------------------------------------------------------------------------
/// @brief Transition the root isolate to the `Phase::Running` phase and
/// invoke the main entrypoint (the "main" method) in the
/// specified library. The isolate must already be in the
/// `Phase::Ready` phase.
///
/// @param[in] library_name The name of the library in which to invoke the
/// supplied entrypoint.
/// @param[in] entrypoint The entrypoint in `library_name`
/// @param[in] args A list of string arguments to the entrypoint.
///
/// @return If the isolate successfully transitioned to the running phase
/// and the main entrypoint was invoked.
///
[[nodiscard]] bool RunFromLibrary(std::optional<std::string> library_name,
std::optional<std::string> entrypoint,
const std::vector<std::string>& args);
//----------------------------------------------------------------------------
/// @brief Transition the isolate to the `Phase::Shutdown` phase. The
/// only thing left to do is to collect the isolate.
///
/// @return If the isolate successfully transitioned to the shutdown
/// phase.
///
[[nodiscard]] bool Shutdown();
//----------------------------------------------------------------------------
/// @brief Registers a callback that will be invoked in isolate scope
/// just before the isolate transitions to the `Phase::Shutdown`
/// phase.
///
/// @param[in] closure The callback to invoke on isolate shutdown.
///
void AddIsolateShutdownCallback(const fml::closure& closure);
//----------------------------------------------------------------------------
/// @brief A weak pointer to the Dart isolate instance. This instance may
/// only be used on the task runner that created the root isolate.
///
/// @return The weak isolate pointer.
///
std::weak_ptr<DartIsolate> GetWeakIsolatePtr();
//----------------------------------------------------------------------------
/// @brief The task runner on which the Dart code for the root isolate is
/// running. For the root isolate, this is the UI task runner for
/// the shell that owns the root isolate.
///
/// @return The message handling task runner.
///
fml::RefPtr<fml::TaskRunner> GetMessageHandlingTaskRunner() const;
bool LoadLoadingUnit(
intptr_t loading_unit_id,
std::unique_ptr<const fml::Mapping> snapshot_data,
std::unique_ptr<const fml::Mapping> snapshot_instructions);
void LoadLoadingUnitError(intptr_t loading_unit_id,
const std::string& error_message,
bool transient);
DartIsolateGroupData& GetIsolateGroupData();
const DartIsolateGroupData& GetIsolateGroupData() const;
/// Returns the "main" entrypoint of the library contained in the kernel
/// data in `mapping`.
static Dart_Handle LoadLibraryFromKernel(
const std::shared_ptr<const fml::Mapping>& mapping);
private:
friend class IsolateConfiguration;
class AutoFireClosure {
public:
explicit AutoFireClosure(const fml::closure& closure);
~AutoFireClosure();
private:
fml::closure closure_;
FML_DISALLOW_COPY_AND_ASSIGN(AutoFireClosure);
};
friend class DartVM;
Phase phase_ = Phase::Unknown;
std::vector<std::unique_ptr<AutoFireClosure>> shutdown_callbacks_;
std::unordered_set<fml::RefPtr<DartSnapshot>> loading_unit_snapshots_;
fml::RefPtr<fml::TaskRunner> message_handling_task_runner_;
const bool may_insecurely_connect_to_all_domains_;
std::string domain_network_policy_;
const bool is_spawning_in_group_;
static std::weak_ptr<DartIsolate> CreateRootIsolate(
const Settings& settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
std::unique_ptr<PlatformConfiguration> platform_configuration,
const Flags& flags,
const fml::closure& isolate_create_callback,
const fml::closure& isolate_shutdown_callback,
const UIDartState::Context& context,
const DartIsolate* spawning_isolate = nullptr);
DartIsolate(const Settings& settings,
bool is_root_isolate,
const UIDartState::Context& context,
bool is_spawning_in_group = false);
//----------------------------------------------------------------------------
/// @brief Initializes the given (current) isolate.
///
/// @param[in] dart_isolate The current isolate that is to be initialized.
///
/// @return Whether the initialization succeeded. Irrespective of whether
/// the initialization suceeded, the current isolate will still be
/// active.
///
[[nodiscard]] bool Initialize(Dart_Isolate dart_isolate);
void SetMessageHandlingTaskRunner(const fml::RefPtr<fml::TaskRunner>& runner);
bool LoadKernel(const std::shared_ptr<const fml::Mapping>& mapping,
bool last_piece);
[[nodiscard]] bool LoadLibraries();
bool UpdateThreadPoolNames() const;
[[nodiscard]] bool MarkIsolateRunnable();
void OnShutdownCallback();
// |Dart_IsolateGroupCreateCallback|
static Dart_Isolate DartIsolateGroupCreateCallback(
const char* advisory_script_uri,
const char* advisory_script_entrypoint,
const char* package_root,
const char* package_config,
Dart_IsolateFlags* flags,
std::shared_ptr<DartIsolate>* parent_isolate_group,
char** error);
// |Dart_IsolateInitializeCallback|
static bool DartIsolateInitializeCallback(void** child_callback_data,
char** error);
static Dart_Isolate DartCreateAndStartServiceIsolate(
const char* package_root,
const char* package_config,
Dart_IsolateFlags* flags,
char** error);
typedef std::function<Dart_Isolate(std::shared_ptr<DartIsolateGroupData>*,
std::shared_ptr<DartIsolate>*,
Dart_IsolateFlags*,
char**)>
IsolateMaker;
static Dart_Isolate CreateDartIsolateGroup(
std::unique_ptr<std::shared_ptr<DartIsolateGroupData>> isolate_group_data,
std::unique_ptr<std::shared_ptr<DartIsolate>> isolate_data,
Dart_IsolateFlags* flags,
char** error,
const IsolateMaker& make_isolate);
static bool InitializeIsolate(
const std::shared_ptr<DartIsolate>& embedder_isolate,
Dart_Isolate isolate,
char** error);
// |Dart_IsolateShutdownCallback|
static void DartIsolateShutdownCallback(
std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
std::shared_ptr<DartIsolate>* isolate_data);
// |Dart_IsolateCleanupCallback|
static void DartIsolateCleanupCallback(
std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
std::shared_ptr<DartIsolate>* isolate_data);
// |Dart_IsolateGroupCleanupCallback|
static void DartIsolateGroupCleanupCallback(
std::shared_ptr<DartIsolateGroupData>* isolate_group_data);
// |Dart_DeferredLoadHandler|
static Dart_Handle OnDartLoadLibrary(intptr_t loading_unit_id);
static void SpawnIsolateShutdownCallback(
std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
std::shared_ptr<DartIsolate>* isolate_data);
FML_DISALLOW_COPY_AND_ASSIGN(DartIsolate);
};
} // namespace flutter
#endif // FLUTTER_RUNTIME_DART_ISOLATE_H_