| // 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 "flutter/sky/engine/wtf/OperatingSystem.h" |
| |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #if defined(OS_WIN) |
| #include <io.h> |
| #include <windows.h> |
| #undef ERROR |
| |
| #define access _access |
| #define R_OK 0x4 |
| |
| #ifndef S_ISDIR |
| #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) |
| #endif |
| |
| #else |
| #include <unistd.h> |
| #endif |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "flutter/assets/directory_asset_bundle.h" |
| #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/files/path.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", "--limit-ints-to-64-bits", |
| }; |
| |
| 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; |
| |
| // Kernel representation of core dart libraries(loaded from platform.dill). |
| // TODO(aam): This (and platform_data below) have to be released when engine |
| // gets torn down. At that point we could also call Dart_Cleanup to complete |
| // Dart VM cleanup. |
| static void* kernel_platform = nullptr; |
| // Bytes actually read from platform.dill that are referenced by kernel_platform |
| static std::vector<uint8_t> platform_data; |
| |
| 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 the isolate that's shutting down is the main one, tell the higher layers |
| // of the stack. |
| if ((dart_state != NULL) && dart_state->is_controller_state()) { |
| dart_state->set_shutting_down(true); |
| if (dart_state->isolate_client()) { |
| dart_state->isolate_client()->DidShutdownMainIsolate(); |
| } |
| } |
| } |
| |
| // The cleanup callback frees the DartState object. |
| void IsolateCleanupCallback(void* callback_data) { |
| UIDartState* dart_state = static_cast<UIDartState*>(callback_data); |
| 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); |
| |
| bool is_running_from_kernel = GetKernelPlatformBinary() != nullptr; |
| |
| Dart_Isolate isolate = |
| is_running_from_kernel |
| ? Dart_CreateIsolateFromKernel( |
| script_uri, "main", kernel_platform, nullptr /* flags */, |
| static_cast<tonic::DartState*>(dart_state), error) |
| : 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() && !is_running_from_kernel, |
| 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 |
| } |
| |
| static bool GetAssetAsBuffer( |
| const std::string& name, |
| std::vector<uint8_t>* data, |
| std::unique_ptr<DirectoryAssetBundle>& directory_asset_bundle, |
| fxl::RefPtr<ZipAssetStore>& asset_store) { |
| return (directory_asset_bundle && |
| directory_asset_bundle->GetAsBuffer(name, data)) || |
| (asset_store && asset_store->GetAsBuffer(name, data)); |
| } |
| |
| 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"); |
| |
| 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; |
| |
| struct stat stat_result = {}; |
| if (::stat(bundle_path.c_str(), &stat_result) == 0) { |
| std::unique_ptr<DirectoryAssetBundle> directory_asset_bundle; |
| // TODO(zarah): Remove usage of zip_asset_store once app.flx is removed. |
| fxl::RefPtr<ZipAssetStore> zip_asset_store; |
| // bundle_path is either the path to app.flx or the flutter assets |
| // directory. |
| std::string flx_path = bundle_path; |
| if (S_ISDIR(stat_result.st_mode)) { |
| directory_asset_bundle = |
| std::make_unique<DirectoryAssetBundle>(bundle_path); |
| flx_path = files::GetDirectoryName(bundle_path) + "/app.flx"; |
| } |
| |
| if (access(flx_path.c_str(), R_OK) == 0) { |
| zip_asset_store = fxl::MakeRefCounted<ZipAssetStore>( |
| GetUnzipperProviderForPath(flx_path)); |
| } |
| GetAssetAsBuffer(kKernelAssetKey, &kernel_data, directory_asset_bundle, |
| zip_asset_store); |
| GetAssetAsBuffer(kSnapshotAssetKey, &snapshot_data, |
| directory_asset_bundle, zip_asset_store); |
| } |
| } |
| } |
| |
| 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* GetKernelPlatformBinary() { |
| return kernel_platform; |
| } |
| |
| 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, |
| const std::string& bundle_path) { |
| 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 |
| |
| if (!bundle_path.empty()) { |
| fxl::RefPtr<blink::DirectoryAssetBundle> directory_asset_bundle = |
| fxl::MakeRefCounted<blink::DirectoryAssetBundle>( |
| std::move(bundle_path)); |
| directory_asset_bundle->GetAsBuffer(kPlatformKernelAssetKey, |
| &platform_data); |
| if (!platform_data.empty()) { |
| kernel_platform = Dart_ReadKernelBinary( |
| platform_data.data(), platform_data.size(), ReleaseFetchedBytes); |
| FXL_DCHECK(kernel_platform != nullptr); |
| } |
| } |
| |
| 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.cleanup = IsolateCleanupCallback; |
| 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 |