// 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. #define FML_USED_ON_EMBEDDER #include "flutter/shell/platform/android/flutter_main.h" #include #include "flutter/fml/command_line.h" #include "flutter/fml/file.h" #include "flutter/fml/macros.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/paths.h" #include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/paths_android.h" #include "flutter/fml/size.h" #include "flutter/lib/ui/plugins/callback_cache.h" #include "flutter/runtime/dart_vm.h" #include "flutter/runtime/start_up.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/switches.h" #include "third_party/dart/runtime/include/dart_tools_api.h" namespace flutter { extern "C" { #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG // Used for debugging dart:* sources. extern const uint8_t kPlatformStrongDill[]; extern const intptr_t kPlatformStrongDillSize; #endif } namespace { fml::jni::ScopedJavaGlobalRef* g_flutter_jni_class = nullptr; } // anonymous namespace FlutterMain::FlutterMain(flutter::Settings settings) : settings_(std::move(settings)), observatory_uri_callback_() {} FlutterMain::~FlutterMain() = default; static std::unique_ptr g_flutter_main; FlutterMain& FlutterMain::Get() { FML_CHECK(g_flutter_main) << "ensureInitializationComplete must have already " "been called."; return *g_flutter_main; } const flutter::Settings& FlutterMain::GetSettings() const { return settings_; } void FlutterMain::Init(JNIEnv* env, jclass clazz, jobject context, jobjectArray jargs, jstring kernelPath, jstring appStoragePath, jstring engineCachesPath) { std::vector args; args.push_back("flutter"); for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) { args.push_back(std::move(arg)); } auto command_line = fml::CommandLineFromIterators(args.begin(), args.end()); auto settings = SettingsFromCommandLine(command_line); // Restore the callback cache. // TODO(chinmaygarde): Route all cache file access through FML and remove this // setter. flutter::DartCallbackCache::SetCachePath( fml::jni::JavaStringToString(env, appStoragePath)); fml::paths::InitializeAndroidCachesPath( fml::jni::JavaStringToString(env, engineCachesPath)); flutter::DartCallbackCache::LoadCacheFromDisk(); if (!flutter::DartVM::IsRunningPrecompiledCode() && kernelPath) { // Check to see if the appropriate kernel files are present and configure // settings accordingly. auto application_kernel_path = fml::jni::JavaStringToString(env, kernelPath); if (fml::IsFile(application_kernel_path)) { settings.application_kernel_asset = application_kernel_path; } } settings.task_observer_add = [](intptr_t key, fml::closure callback) { fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); }; settings.task_observer_remove = [](intptr_t key) { fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); }; #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG // There are no ownership concerns here as all mappings are owned by the // embedder and not the engine. auto make_mapping_callback = [](const uint8_t* mapping, size_t size) { return [mapping, size]() { return std::make_unique(mapping, size); }; }; settings.dart_library_sources_kernel = make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize); #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG // Not thread safe. Will be removed when FlutterMain is refactored to no // longer be a singleton. g_flutter_main.reset(new FlutterMain(std::move(settings))); g_flutter_main->SetupObservatoryUriCallback(env); } void FlutterMain::SetupObservatoryUriCallback(JNIEnv* env) { g_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef( env, env->FindClass("io/flutter/embedding/engine/FlutterJNI")); if (g_flutter_jni_class->is_null()) { return; } jfieldID uri_field = env->GetStaticFieldID( g_flutter_jni_class->obj(), "observatoryUri", "Ljava/lang/String;"); if (uri_field == nullptr) { return; } auto set_uri = [env, uri_field](std::string uri) { fml::jni::ScopedJavaLocalRef java_uri = fml::jni::StringToJavaString(env, uri); env->SetStaticObjectField(g_flutter_jni_class->obj(), uri_field, java_uri.obj()); }; fml::MessageLoop::EnsureInitializedForCurrentThread(); fml::RefPtr platform_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); observatory_uri_callback_ = DartServiceIsolate::AddServerStatusCallback( [platform_runner, set_uri](std::string uri) { platform_runner->PostTask([uri, set_uri] { set_uri(uri); }); }); } static void RecordStartTimestamp(JNIEnv* env, jclass jcaller, jlong initTimeMillis) { int64_t initTimeMicros = static_cast(initTimeMillis) * static_cast(1000); flutter::engine_main_enter_ts = Dart_TimelineGetMicros() - initTimeMicros; } bool FlutterMain::Register(JNIEnv* env) { static const JNINativeMethod methods[] = { { .name = "nativeInit", .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/" "lang/String;Ljava/lang/String;Ljava/lang/String;)V", .fnPtr = reinterpret_cast(&Init), }, { .name = "nativeRecordStartTimestamp", .signature = "(J)V", .fnPtr = reinterpret_cast(&RecordStartTimestamp), }, }; jclass clazz = env->FindClass("io/flutter/embedding/engine/FlutterJNI"); if (clazz == nullptr) { return false; } return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0; } } // namespace flutter