mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
The Android embedder had been using a JNI call to get the observatory URI from DartServiceIsolate. This call was not thread safe and was redundant with the server status callback mechanism used on iOS.
193 lines
6.2 KiB
C++
193 lines
6.2 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.
|
|
|
|
#define FML_USED_ON_EMBEDDER
|
|
|
|
#include "flutter/shell/platform/android/flutter_main.h"
|
|
|
|
#include <vector>
|
|
|
|
#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<jclass>* g_flutter_jni_class = nullptr;
|
|
|
|
} // anonymous namespace
|
|
|
|
FlutterMain::FlutterMain(flutter::Settings settings)
|
|
: settings_(std::move(settings)), observatory_uri_callback_() {}
|
|
|
|
FlutterMain::~FlutterMain() {
|
|
if (observatory_uri_callback_) {
|
|
DartServiceIsolate::RemoveServerStatusCallback(observatory_uri_callback_);
|
|
}
|
|
}
|
|
|
|
static std::unique_ptr<FlutterMain> 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 bundlePath,
|
|
jstring appStoragePath,
|
|
jstring engineCachesPath) {
|
|
std::vector<std::string> 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);
|
|
|
|
settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);
|
|
|
|
// 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()) {
|
|
// Check to see if the appropriate kernel files are present and configure
|
|
// settings accordingly.
|
|
auto application_kernel_path =
|
|
fml::paths::JoinPaths({settings.assets_path, "kernel_blob.bin"});
|
|
|
|
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<fml::NonOwnedMapping>(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<jclass>(
|
|
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<jstring> java_uri =
|
|
fml::jni::StringToJavaString(env, uri);
|
|
env->SetStaticObjectField(g_flutter_jni_class->obj(), uri_field,
|
|
java_uri.obj());
|
|
};
|
|
|
|
fml::MessageLoop::EnsureInitializedForCurrentThread();
|
|
fml::RefPtr<fml::TaskRunner> 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<int64_t>(initTimeMillis) * static_cast<int64_t>(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<void*>(&Init),
|
|
},
|
|
{
|
|
.name = "nativeRecordStartTimestamp",
|
|
.signature = "(J)V",
|
|
.fnPtr = reinterpret_cast<void*>(&RecordStartTimestamp),
|
|
},
|
|
};
|
|
|
|
jclass clazz = env->FindClass("io/flutter/view/FlutterMain");
|
|
|
|
if (clazz == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0;
|
|
}
|
|
|
|
} // namespace flutter
|