mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Send the isolate service ID from the engine to the embedder (#9324)
Applications can use an embedder API to obtain the isolate ID and then use it in calls to the Dart service protocol.
This commit is contained in:
parent
675033fc05
commit
ea7ca9804a
@ -141,6 +141,13 @@ DartIsolate::Phase DartIsolate::GetPhase() const {
|
||||
return phase_;
|
||||
}
|
||||
|
||||
std::string DartIsolate::GetServiceId() {
|
||||
const char* service_id_buf = Dart_IsolateServiceId(isolate());
|
||||
std::string service_id(service_id_buf);
|
||||
free(const_cast<char*>(service_id_buf));
|
||||
return service_id;
|
||||
}
|
||||
|
||||
bool DartIsolate::Initialize(Dart_Isolate dart_isolate, bool is_root_isolate) {
|
||||
TRACE_EVENT0("flutter", "DartIsolate::Initialize");
|
||||
if (phase_ != Phase::Uninitialized) {
|
||||
|
||||
@ -73,6 +73,8 @@ class DartIsolate : public UIDartState {
|
||||
|
||||
Phase GetPhase() const;
|
||||
|
||||
std::string GetServiceId();
|
||||
|
||||
FML_WARN_UNUSED_RESULT
|
||||
bool PrepareForRunningFromPrecompiledCode();
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ static constexpr char kLifecycleChannel[] = "flutter/lifecycle";
|
||||
static constexpr char kNavigationChannel[] = "flutter/navigation";
|
||||
static constexpr char kLocalizationChannel[] = "flutter/localization";
|
||||
static constexpr char kSettingsChannel[] = "flutter/settings";
|
||||
static constexpr char kIsolateChannel[] = "flutter/isolate";
|
||||
|
||||
Engine::Engine(Delegate& delegate,
|
||||
DartVM& vm,
|
||||
@ -145,6 +146,14 @@ Engine::RunStatus Engine::Run(RunConfiguration configuration) {
|
||||
isolate->AddIsolateShutdownCallback(
|
||||
settings_.root_isolate_shutdown_callback);
|
||||
}
|
||||
|
||||
std::string service_id = isolate->GetServiceId();
|
||||
fml::RefPtr<PlatformMessage> service_id_message =
|
||||
fml::MakeRefCounted<flutter::PlatformMessage>(
|
||||
kIsolateChannel,
|
||||
std::vector<uint8_t>(service_id.begin(), service_id.end()),
|
||||
nullptr);
|
||||
HandlePlatformMessage(service_id_message);
|
||||
}
|
||||
|
||||
return isolate_running ? Engine::RunStatus::Success
|
||||
|
||||
@ -14,6 +14,7 @@ import java.nio.ByteBuffer;
|
||||
|
||||
import io.flutter.embedding.engine.FlutterJNI;
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.StringCodec;
|
||||
import io.flutter.view.FlutterCallbackInformation;
|
||||
|
||||
/**
|
||||
@ -44,10 +45,24 @@ public class DartExecutor implements BinaryMessenger {
|
||||
@NonNull
|
||||
private final DartMessenger messenger;
|
||||
private boolean isApplicationRunning = false;
|
||||
private String isolateServiceId;
|
||||
private IsolateServiceIdListener isolateServiceIdListener;
|
||||
|
||||
private final BinaryMessenger.BinaryMessageHandler isolateChannelMessageHandler =
|
||||
new BinaryMessenger.BinaryMessageHandler() {
|
||||
@Override
|
||||
public void onMessage(ByteBuffer message, final BinaryReply callback) {
|
||||
isolateServiceId = StringCodec.INSTANCE.decodeMessage(message);
|
||||
if (isolateServiceIdListener != null) {
|
||||
isolateServiceIdListener.onIsolateServiceIdAvailable(isolateServiceId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public DartExecutor(@NonNull FlutterJNI flutterJNI) {
|
||||
this.flutterJNI = flutterJNI;
|
||||
this.messenger = new DartMessenger(flutterJNI);
|
||||
messenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,6 +196,32 @@ public class DartExecutor implements BinaryMessenger {
|
||||
}
|
||||
//------ END BinaryMessenger -----
|
||||
|
||||
/**
|
||||
* Returns an identifier for this executor's primary isolate. This identifier can be used
|
||||
* in queries to the Dart service protocol.
|
||||
*/
|
||||
public String getIsolateServiceId() {
|
||||
return isolateServiceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface invoked when the isolate identifier becomes available.
|
||||
*/
|
||||
interface IsolateServiceIdListener {
|
||||
void onIsolateServiceIdAvailable(String isolateServiceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a listener that will be notified when an isolate identifier is available for this
|
||||
* executor's primary isolate.
|
||||
*/
|
||||
public void setIsolateServiceIdListener(IsolateServiceIdListener listener) {
|
||||
isolateServiceIdListener = listener;
|
||||
if (isolateServiceIdListener != null && isolateServiceId != null) {
|
||||
isolateServiceIdListener.onIsolateServiceIdAvailable(isolateServiceId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options that specify which Dart entrypoint function is executed and where
|
||||
* to find that entrypoint and other assets required for Dart execution.
|
||||
@ -286,4 +327,4 @@ public class DartExecutor implements BinaryMessenger {
|
||||
this.callbackHandle = callbackHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,11 @@ EmbedderConfigBuilder::EmbedderConfigBuilder(
|
||||
InitializationPreference preference)
|
||||
: context_(context) {
|
||||
project_args_.struct_size = sizeof(project_args_);
|
||||
project_args_.platform_message_callback =
|
||||
[](const FlutterPlatformMessage* message, void* context) {
|
||||
reinterpret_cast<EmbedderContext*>(context)->PlatformMessageCallback(
|
||||
message);
|
||||
};
|
||||
|
||||
custom_task_runners_.struct_size = sizeof(FlutterCustomTaskRunners);
|
||||
|
||||
@ -126,6 +131,11 @@ void EmbedderConfigBuilder::SetPlatformTaskRunner(
|
||||
project_args_.custom_task_runners = &custom_task_runners_;
|
||||
}
|
||||
|
||||
void EmbedderConfigBuilder::SetPlatformMessageCallback(
|
||||
std::function<void(const FlutterPlatformMessage*)> callback) {
|
||||
context_.SetPlatformMessageCallback(callback);
|
||||
}
|
||||
|
||||
UniqueEngine EmbedderConfigBuilder::LaunchEngine() {
|
||||
FlutterEngine engine = nullptr;
|
||||
|
||||
|
||||
@ -58,6 +58,9 @@ class EmbedderConfigBuilder {
|
||||
|
||||
void SetPlatformTaskRunner(const FlutterTaskRunnerDescription* runner);
|
||||
|
||||
void SetPlatformMessageCallback(
|
||||
std::function<void(const FlutterPlatformMessage*)> callback);
|
||||
|
||||
UniqueEngine LaunchEngine();
|
||||
|
||||
private:
|
||||
|
||||
@ -91,6 +91,18 @@ void EmbedderContext::SetSemanticsCustomActionCallback(
|
||||
update_semantics_custom_action_callback;
|
||||
}
|
||||
|
||||
void EmbedderContext::SetPlatformMessageCallback(
|
||||
std::function<void(const FlutterPlatformMessage*)> callback) {
|
||||
platform_message_callback_ = callback;
|
||||
}
|
||||
|
||||
void EmbedderContext::PlatformMessageCallback(
|
||||
const FlutterPlatformMessage* message) {
|
||||
if (platform_message_callback_) {
|
||||
platform_message_callback_(message);
|
||||
}
|
||||
}
|
||||
|
||||
FlutterUpdateSemanticsNodeCallback
|
||||
EmbedderContext::GetUpdateSemanticsNodeCallbackHook() {
|
||||
return [](const FlutterSemanticsNode* semantics_node, void* user_data) {
|
||||
|
||||
@ -49,6 +49,9 @@ class EmbedderContext {
|
||||
void SetSemanticsCustomActionCallback(
|
||||
SemanticsActionCallback semantics_custom_action);
|
||||
|
||||
void SetPlatformMessageCallback(
|
||||
std::function<void(const FlutterPlatformMessage*)> callback);
|
||||
|
||||
private:
|
||||
// This allows the builder to access the hooks.
|
||||
friend class EmbedderConfigBuilder;
|
||||
@ -63,6 +66,7 @@ class EmbedderContext {
|
||||
SemanticsNodeCallback update_semantics_node_callback_;
|
||||
SemanticsActionCallback update_semantics_custom_action_callback_;
|
||||
std::unique_ptr<EmbedderTestGLSurface> gl_surface_; // lazy
|
||||
std::function<void(const FlutterPlatformMessage*)> platform_message_callback_;
|
||||
|
||||
static VoidCallback GetIsolateCreateCallbackHook();
|
||||
|
||||
@ -90,6 +94,8 @@ class EmbedderContext {
|
||||
|
||||
void* GLGetProcAddress(const char* name);
|
||||
|
||||
void PlatformMessageCallback(const FlutterPlatformMessage* message);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderContext);
|
||||
};
|
||||
|
||||
|
||||
@ -216,5 +216,50 @@ TEST_F(EmbedderTest, CanCreateOpenGLRenderingEngine) {
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, IsolateServiceIdSent) {
|
||||
auto& context = GetEmbedderContext();
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
|
||||
fml::Thread thread;
|
||||
UniqueEngine engine;
|
||||
std::string isolate_message;
|
||||
|
||||
EmbedderTestTaskRunner runner(
|
||||
[&](FlutterTask task) { FlutterEngineRunTask(engine.get(), &task); });
|
||||
|
||||
thread.GetTaskRunner()->PostTask([&]() {
|
||||
EmbedderConfigBuilder builder(context);
|
||||
const auto task_runner_description = runner.GetEmbedderDescription();
|
||||
runner.SetForwardingTaskRunner(
|
||||
fml::MessageLoop::GetCurrent().GetTaskRunner());
|
||||
builder.SetPlatformTaskRunner(&task_runner_description);
|
||||
builder.SetDartEntrypoint("main");
|
||||
builder.SetPlatformMessageCallback(
|
||||
[&](const FlutterPlatformMessage* message) {
|
||||
if (strcmp(message->channel, "flutter/isolate") == 0) {
|
||||
isolate_message = {reinterpret_cast<const char*>(message->message),
|
||||
message->message_size};
|
||||
latch.Signal();
|
||||
}
|
||||
});
|
||||
engine = builder.LaunchEngine();
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
});
|
||||
|
||||
// Wait for the isolate ID message and check its format.
|
||||
latch.Wait();
|
||||
ASSERT_EQ(isolate_message.find("isolates/"), 0ul);
|
||||
|
||||
// Since the engine was started on its own thread, it must be killed there as
|
||||
// well.
|
||||
fml::AutoResetWaitableEvent kill_latch;
|
||||
thread.GetTaskRunner()->PostTask(
|
||||
fml::MakeCopyable([&engine, &kill_latch]() mutable {
|
||||
engine.reset();
|
||||
kill_latch.Signal();
|
||||
}));
|
||||
kill_latch.Wait();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user