mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Snapshots compiled with sound null-safety enabled require changes to the way in which isolates are launched. Specifically, the `Dart_IsolateFlags::null_safety` field needs to be known upfront. The value of this field can only be determined once the kernel snapshot is available. This poses a problem in the engine because the engine used to launch the isolate at shell initialization and only need the kernel mappings later at isolate launch (when transitioning the root isolate to the `DartIsolate::Phase::Running` phase). This patch delays launch of the isolate on the UI task runner till a kernel mapping is available. The side effects of this delay (callers no longer having access to the non-running isolate handle) have been addressed in this patch. The DartIsolate API has also been amended to hide the method that could return a non-running isolate to the caller. Instead, it has been replaced with a method that requires a valid isolate configuration that returns a running root isolate. The isolate will be launched by asking the isolate configuration for its null-safety characteristics. A side effect of enabling null-safety is that Dart APIs that work with legacy types will now terminate the process if used with an isolate that has sound null-safety enabled. These APIs may no longer be used in the engine. This primarily affects the Dart Convertors in Tonic that convert certain C++ objects into the Dart counterparts. All known Dart Converters have been updated to convert C++ objects to non-nullable Dart types inferred using type traits of the corresponding C++ object. The few spots in the engine that used the old Dart APIs directly have been manually updated. To ensure that no usage of the legacy APIs remain in the engine (as these would cause runtime process terminations), the legacy APIs were prefixed with the `DART_LEGACY_API` macro and the macro defined to `[[deprecated]]` in all engine translation units. While the engine now primarily works with non-nullable Dart types, callers can still use `Dart_TypeToNonNullableType` to acquire nullable types for use directly or with Tonic. One use case that is not addressed with the Tonic Dart Convertors is the creation of non-nullable lists of nullable types. This hasn’t come up so far in the engine. A minor related change is reworking tonic to define a single library target. This allows the various tonic subsystems to depend on one another. Primarily, this is used to make the Dart convertors use the logging utilities. This now allows errors to be more descriptive as the presence of error handles is caught (and logged) earlier. Fixes https://github.com/flutter/flutter/issues/59879
172 lines
8.1 KiB
C++
172 lines
8.1 KiB
C++
// 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_SHELL_RUNTIME_ISOLATE_CONFIGURATION_H_
|
|
#define FLUTTER_SHELL_RUNTIME_ISOLATE_CONFIGURATION_H_
|
|
|
|
#include <future>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "flutter/assets/asset_manager.h"
|
|
#include "flutter/assets/asset_resolver.h"
|
|
#include "flutter/common/settings.h"
|
|
#include "flutter/fml/macros.h"
|
|
#include "flutter/fml/mapping.h"
|
|
#include "flutter/fml/memory/weak_ptr.h"
|
|
#include "flutter/runtime/dart_isolate.h"
|
|
|
|
namespace flutter {
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// @brief An isolate configuration is a collection of snapshots and asset
|
|
/// managers that the engine will use to configure the isolate
|
|
/// before invoking its root entrypoint. The set of snapshots must
|
|
/// be sufficient for the engine to move the isolate from the
|
|
/// |DartIsolate::Phase::LibrariesSetup| phase to the
|
|
/// |DartIsolate::Phase::Ready| phase. Note that the isolate
|
|
/// configuration will not be collected till the isolate tied to the
|
|
/// configuration as well as any and all child isolates of that
|
|
/// isolate are collected. The engine may ask the configuration to
|
|
/// prepare multiple isolates. All subclasses of this class must be
|
|
/// thread safe as the configuration may be created, collected and
|
|
/// used on multiple threads. Usually these threads are engine or VM
|
|
/// managed so care must be taken to ensure that subclasses do not
|
|
/// reference any thread local state.
|
|
///
|
|
class IsolateConfiguration {
|
|
public:
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Attempts to infer the isolate configuration from the
|
|
/// `Settings` object. If the VM is configured for AOT mode,
|
|
/// snapshot resolution is attempted with predefined symbols
|
|
/// present in the currently loaded process. In JIT mode, Dart
|
|
/// kernel file resolution is attempted in the assets directory.
|
|
/// If an IO worker is specified, snapshot resolution may be
|
|
/// attempted on the serial worker task runner. The worker task
|
|
/// runner thread must remain valid and running till after the
|
|
/// shell associated with the engine used to launch the isolate
|
|
/// for which this run configuration is used is collected.
|
|
///
|
|
/// @param[in] settings The settings
|
|
/// @param[in] asset_manager The optional asset manager. This is used when
|
|
/// using the legacy settings fields that specify
|
|
/// the asset by name instead of a mappings
|
|
/// callback.
|
|
/// @param[in] io_worker An optional IO worker. Specify `nullptr` is a
|
|
/// worker should not be used or one is not
|
|
/// available.
|
|
///
|
|
/// @return An isolate configuration if one can be inferred from the
|
|
/// settings. If not, returns `nullptr`.
|
|
///
|
|
[[nodiscard]] static std::unique_ptr<IsolateConfiguration> InferFromSettings(
|
|
const Settings& settings,
|
|
std::shared_ptr<AssetManager> asset_manager = nullptr,
|
|
fml::RefPtr<fml::TaskRunner> io_worker = nullptr);
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Creates an AOT isolate configuration using snapshot symbols
|
|
/// present in the currently loaded process. These symbols need to
|
|
/// be given to the Dart VM on bootstrap and hence have already
|
|
/// been resolved.
|
|
///
|
|
/// @return An AOT isolate configuration.
|
|
///
|
|
static std::unique_ptr<IsolateConfiguration> CreateForAppSnapshot();
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Creates a JIT isolate configuration using a list of futures to
|
|
/// snapshots defining the ready isolate state. In environments
|
|
/// where snapshot resolution is extremely expensive, embedders
|
|
/// attempt to resolve snapshots on worker thread(s) and return
|
|
/// the future of the promise of snapshot resolution to this
|
|
/// method. That way, snapshot resolution begins well before
|
|
/// isolate launch is attempted by the engine.
|
|
///
|
|
/// @param[in] kernel_pieces The list of futures to Dart kernel snapshots.
|
|
///
|
|
/// @return A JIT isolate configuration.
|
|
///
|
|
static std::unique_ptr<IsolateConfiguration> CreateForKernelList(
|
|
std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
|
|
kernel_pieces);
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Creates a JIT isolate configuration using the specified
|
|
/// snapshot. This is a convenience method for the
|
|
/// `CreateForKernelList` method that takes a list of futures to
|
|
/// Dart kernel snapshots.
|
|
///
|
|
/// @see CreateForKernelList()
|
|
///
|
|
/// @param[in] kernel The kernel snapshot.
|
|
///
|
|
/// @return A JIT isolate configuration.
|
|
///
|
|
static std::unique_ptr<IsolateConfiguration> CreateForKernel(
|
|
std::unique_ptr<const fml::Mapping> kernel);
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Creates a JIT isolate configuration using the specified
|
|
/// snapshots. This is a convenience method for the
|
|
/// `CreateForKernelList` method that takes a list of futures to
|
|
/// Dart kernel snapshots.
|
|
///
|
|
/// @see CreateForKernelList()
|
|
///
|
|
/// @param[in] kernel_pieces The kernel pieces
|
|
///
|
|
/// @return { description_of_the_return_value }
|
|
///
|
|
static std::unique_ptr<IsolateConfiguration> CreateForKernelList(
|
|
std::vector<std::unique_ptr<const fml::Mapping>> kernel_pieces);
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Create an isolate configuration. This has no threading
|
|
/// restrictions.
|
|
///
|
|
IsolateConfiguration();
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Destroys an isolate configuration. This has no threading
|
|
/// restrictions and may be collection of configurations may occur
|
|
/// on any thread (and usually happens on an internal VM managed
|
|
/// thread pool thread).
|
|
///
|
|
virtual ~IsolateConfiguration();
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief When an isolate is created and sufficiently initialized to
|
|
/// move it into the `DartIsolate::Phase::LibrariesSetup` phase,
|
|
/// this method is invoked on the isolate to then move the isolate
|
|
/// into the `DartIsolate::Phase::Ready` phase. Then isolate's
|
|
/// main entrypoint is then invoked to move it into the
|
|
/// `DartIsolate::Phase::Running` phase. This method will be
|
|
/// called each time the root isolate is launched (which may be
|
|
/// multiple times in cold-restart scenarios) as well as one each
|
|
/// for any child isolates referenced by that isolate.
|
|
///
|
|
/// @param isolate The isolate which is already in the
|
|
/// `DartIsolate::Phase::LibrariesSetup` phase.
|
|
///
|
|
/// @return Returns true if the isolate could be configured. Unless this
|
|
/// returns true, the engine will not move the isolate to the
|
|
/// `DartIsolate::Phase::Ready` phase for subsequent run.
|
|
///
|
|
[[nodiscard]] bool PrepareIsolate(DartIsolate& isolate);
|
|
|
|
virtual bool IsNullSafetyEnabled(const DartSnapshot& snapshot) = 0;
|
|
|
|
protected:
|
|
virtual bool DoPrepareIsolate(DartIsolate& isolate) = 0;
|
|
|
|
private:
|
|
FML_DISALLOW_COPY_AND_ASSIGN(IsolateConfiguration);
|
|
};
|
|
|
|
} // namespace flutter
|
|
|
|
#endif // FLUTTER_SHELL_RUNTIME_ISOLATE_CONFIGURATION_H_
|