mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
592 lines
21 KiB
C++
592 lines
21 KiB
C++
// 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 <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#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/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 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",
|
|
};
|
|
|
|
static const char* kDartPrecompilationArgs[] = {
|
|
"--precompilation",
|
|
};
|
|
|
|
static const char* kDartWriteProtectCodeArgs[] FXL_ALLOW_UNUSED_TYPE = {
|
|
"--no_write_protect_code",
|
|
};
|
|
|
|
static const char* kDartCheckedModeArgs[] = {
|
|
// clang-format off
|
|
"--enable_asserts",
|
|
"--enable_type_checks",
|
|
"--error_on_bad_type",
|
|
"--error_on_bad_override",
|
|
// 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;
|
|
|
|
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<UIDartState*>(callback_data);
|
|
if ((dart_state != NULL) && !dart_state->is_controller_state()) {
|
|
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,
|
|
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);
|
|
Dart_Isolate isolate =
|
|
Dart_CreateIsolate(script_uri, "main", g_default_isolate_snapshot_data,
|
|
g_default_isolate_snapshot_instructions, nullptr,
|
|
static_cast<tonic::DartState*>(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(), 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
|
|
}
|
|
|
|
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, error);
|
|
}
|
|
|
|
std::string entry_uri = script_uri;
|
|
// Are we running from a Dart source file?
|
|
const bool running_from_source = StringEndsWith(entry_uri, ".dart");
|
|
|
|
void* kernel_platform = nullptr;
|
|
std::vector<uint8_t> kernel_data;
|
|
std::vector<uint8_t> 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 (!running_from_source) {
|
|
// Attempt to copy the snapshot from the asset bundle.
|
|
const std::string& bundle_path = entry_path;
|
|
fxl::RefPtr<ZipAssetStore> zip_asset_store =
|
|
fxl::MakeRefCounted<ZipAssetStore>(
|
|
GetUnzipperProviderForPath(std::move(bundle_path)));
|
|
zip_asset_store->GetAsBuffer(kKernelAssetKey, &kernel_data);
|
|
zip_asset_store->GetAsBuffer(kSnapshotAssetKey, &snapshot_data);
|
|
|
|
std::vector<uint8_t> platform_data;
|
|
zip_asset_store->GetAsBuffer(kPlatformKernelAssetKey, &platform_data);
|
|
if (!platform_data.empty()) {
|
|
kernel_platform = Dart_ReadKernelBinary(
|
|
platform_data.data(), platform_data.size(), ReleaseFetchedBytes);
|
|
FXL_DCHECK(kernel_platform != NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
UIDartState* parent_dart_state = static_cast<UIDartState*>(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<DartClassProvider> 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_LoadKernel(Dart_ReadKernelBinary(
|
|
kernel_data.data(), kernel_data.size(), ReleaseFetchedBytes))));
|
|
} 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;
|
|
#else // FLUTTER_RUNTIME_MODE
|
|
return tonic::DartConverter<tonic::Uint8List>::ToDart(
|
|
::dart::observatory::observatory_assets_archive,
|
|
::dart::observatory::observatory_assets_archive_len);
|
|
#endif // FLUTTER_RUNTIME_MODE
|
|
}
|
|
|
|
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<EmbedderTracingCallbacks> 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<const char*> 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 {
|
|
// Dart assumes ARM devices are insufficiently powerful and sets the
|
|
// default profile period to 100Hz. This number is suitable for older
|
|
// Raspberry Pi devices but quite low for current smartphones.
|
|
"--profile_period=1000",
|
|
// 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<const char*>* 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 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) {
|
|
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<const char*> 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) && 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
|
|
// 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
|
|
|
|
#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 (use_checked_mode)
|
|
PushBackAll(&args, kDartCheckedModeArgs, arraysize(kDartCheckedModeArgs));
|
|
|
|
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();
|
|
|
|
// 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.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
|