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:
Jason Simmons 2019-06-17 16:02:26 -07:00 committed by GitHub
parent 675033fc05
commit ea7ca9804a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 136 additions and 1 deletions

View File

@ -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) {

View File

@ -73,6 +73,8 @@ class DartIsolate : public UIDartState {
Phase GetPhase() const;
std::string GetServiceId();
FML_WARN_UNUSED_RESULT
bool PrepareForRunningFromPrecompiledCode();

View File

@ -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

View File

@ -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;
}
}
}
}

View File

@ -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;

View File

@ -58,6 +58,9 @@ class EmbedderConfigBuilder {
void SetPlatformTaskRunner(const FlutterTaskRunnerDescription* runner);
void SetPlatformMessageCallback(
std::function<void(const FlutterPlatformMessage*)> callback);
UniqueEngine LaunchEngine();
private:

View File

@ -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) {

View File

@ -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);
};

View File

@ -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