1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #define FML_USED_ON_EMBEDDER
6
7 #include "flutter/shell/platform/android/flutter_main.h"
8
9 #include <vector>
10
11 #include "flutter/fml/command_line.h"
12 #include "flutter/fml/file.h"
13 #include "flutter/fml/macros.h"
14 #include "flutter/fml/message_loop.h"
15 #include "flutter/fml/paths.h"
16 #include "flutter/fml/platform/android/jni_util.h"
17 #include "flutter/fml/platform/android/paths_android.h"
18 #include "flutter/fml/size.h"
19 #include "flutter/lib/ui/plugins/callback_cache.h"
20 #include "flutter/runtime/dart_vm.h"
21 #include "flutter/runtime/start_up.h"
22 #include "flutter/shell/common/shell.h"
23 #include "flutter/shell/common/switches.h"
24
25 namespace flutter {
26
27 extern "C" {
28 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
29 // Used for debugging dart:* sources.
30 extern const uint8_t kPlatformStrongDill[];
31 extern const intptr_t kPlatformStrongDillSize;
32 #endif
33 }
34
35 namespace {
36
37 fml::jni::ScopedJavaGlobalRef<jclass>* g_flutter_jni_class = nullptr;
38
39 } // anonymous namespace
40
FlutterMain(flutter::Settings settings)41 FlutterMain::FlutterMain(flutter::Settings settings)
42 : settings_(std::move(settings)), observatory_uri_callback_() {}
43
44 FlutterMain::~FlutterMain() = default;
45
46 static std::unique_ptr<FlutterMain> g_flutter_main;
47
Get()48 FlutterMain& FlutterMain::Get() {
49 FML_CHECK(g_flutter_main) << "ensureInitializationComplete must have already "
50 "been called.";
51 return *g_flutter_main;
52 }
53
GetSettings() const54 const flutter::Settings& FlutterMain::GetSettings() const {
55 return settings_;
56 }
57
Init(JNIEnv * env,jclass clazz,jobject context,jobjectArray jargs,jstring kernelPath,jstring appStoragePath,jstring engineCachesPath)58 void FlutterMain::Init(JNIEnv* env,
59 jclass clazz,
60 jobject context,
61 jobjectArray jargs,
62 jstring kernelPath,
63 jstring appStoragePath,
64 jstring engineCachesPath) {
65 std::vector<std::string> args;
66 args.push_back("flutter");
67 for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
68 args.push_back(std::move(arg));
69 }
70 auto command_line = fml::CommandLineFromIterators(args.begin(), args.end());
71
72 auto settings = SettingsFromCommandLine(command_line);
73
74 // Restore the callback cache.
75 // TODO(chinmaygarde): Route all cache file access through FML and remove this
76 // setter.
77 flutter::DartCallbackCache::SetCachePath(
78 fml::jni::JavaStringToString(env, appStoragePath));
79
80 fml::paths::InitializeAndroidCachesPath(
81 fml::jni::JavaStringToString(env, engineCachesPath));
82
83 flutter::DartCallbackCache::LoadCacheFromDisk();
84
85 if (!flutter::DartVM::IsRunningPrecompiledCode() && kernelPath) {
86 // Check to see if the appropriate kernel files are present and configure
87 // settings accordingly.
88 auto application_kernel_path =
89 fml::jni::JavaStringToString(env, kernelPath);
90
91 if (fml::IsFile(application_kernel_path)) {
92 settings.application_kernel_asset = application_kernel_path;
93 }
94 }
95
96 settings.task_observer_add = [](intptr_t key, fml::closure callback) {
97 fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
98 };
99
100 settings.task_observer_remove = [](intptr_t key) {
101 fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
102 };
103
104 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
105 // There are no ownership concerns here as all mappings are owned by the
106 // embedder and not the engine.
107 auto make_mapping_callback = [](const uint8_t* mapping, size_t size) {
108 return [mapping, size]() {
109 return std::make_unique<fml::NonOwnedMapping>(mapping, size);
110 };
111 };
112
113 settings.dart_library_sources_kernel =
114 make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize);
115 #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
116
117 // Not thread safe. Will be removed when FlutterMain is refactored to no
118 // longer be a singleton.
119 g_flutter_main.reset(new FlutterMain(std::move(settings)));
120
121 g_flutter_main->SetupObservatoryUriCallback(env);
122 }
123
SetupObservatoryUriCallback(JNIEnv * env)124 void FlutterMain::SetupObservatoryUriCallback(JNIEnv* env) {
125 g_flutter_jni_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
126 env, env->FindClass("io/flutter/embedding/engine/FlutterJNI"));
127 if (g_flutter_jni_class->is_null()) {
128 return;
129 }
130 jfieldID uri_field = env->GetStaticFieldID(
131 g_flutter_jni_class->obj(), "observatoryUri", "Ljava/lang/String;");
132 if (uri_field == nullptr) {
133 return;
134 }
135
136 auto set_uri = [env, uri_field](std::string uri) {
137 fml::jni::ScopedJavaLocalRef<jstring> java_uri =
138 fml::jni::StringToJavaString(env, uri);
139 env->SetStaticObjectField(g_flutter_jni_class->obj(), uri_field,
140 java_uri.obj());
141 };
142
143 fml::MessageLoop::EnsureInitializedForCurrentThread();
144 fml::RefPtr<fml::TaskRunner> platform_runner =
145 fml::MessageLoop::GetCurrent().GetTaskRunner();
146
147 observatory_uri_callback_ = DartServiceIsolate::AddServerStatusCallback(
148 [platform_runner, set_uri](std::string uri) {
149 platform_runner->PostTask([uri, set_uri] { set_uri(uri); });
150 });
151 }
152
RecordStartTimestamp(JNIEnv * env,jclass jcaller,jlong initTimeMillis)153 static void RecordStartTimestamp(JNIEnv* env,
154 jclass jcaller,
155 jlong initTimeMillis) {
156 int64_t initTimeMicros =
157 static_cast<int64_t>(initTimeMillis) * static_cast<int64_t>(1000);
158 flutter::engine_main_enter_ts = 0 - initTimeMicros;
159 }
160
Register(JNIEnv * env)161 bool FlutterMain::Register(JNIEnv* env) {
162 static const JNINativeMethod methods[] = {
163 {
164 .name = "nativeInit",
165 .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/"
166 "lang/String;Ljava/lang/String;Ljava/lang/String;)V",
167 .fnPtr = reinterpret_cast<void*>(&Init),
168 },
169 {
170 .name = "nativeRecordStartTimestamp",
171 .signature = "(J)V",
172 .fnPtr = reinterpret_cast<void*>(&RecordStartTimestamp),
173 },
174 };
175
176 jclass clazz = env->FindClass("io/flutter/embedding/engine/FlutterJNI");
177
178 if (clazz == nullptr) {
179 return false;
180 }
181
182 return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0;
183 }
184
185 } // namespace flutter
186