Skip to content

Commit

Permalink
Send the isolate service ID from the engine to the embedder (flutter#…
Browse files Browse the repository at this point in the history
…9324)

Applications can use an embedder API to obtain the isolate ID and then use it
in calls to the Dart service protocol.
  • Loading branch information
jason-simmons authored Jun 17, 2019
1 parent 675033f commit ea7ca98
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 1 deletion.
7 changes: 7 additions & 0 deletions runtime/dart_isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions runtime/dart_isolate.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class DartIsolate : public UIDartState {

Phase GetPhase() const;

std::string GetServiceId();

FML_WARN_UNUSED_RESULT
bool PrepareForRunningFromPrecompiledCode();

Expand Down
9 changes: 9 additions & 0 deletions shell/common/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StringCodec;
import io.flutter.view.FlutterCallbackInformation;

/**
Expand Down Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -181,6 +196,32 @@ public void setMessageHandler(@NonNull String channel, @Nullable 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.
Expand Down Expand Up @@ -286,4 +327,4 @@ public DartCallback(
this.callbackHandle = callbackHandle;
}
}
}
}
10 changes: 10 additions & 0 deletions shell/platform/embedder/tests/embedder_config_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;

Expand Down
3 changes: 3 additions & 0 deletions shell/platform/embedder/tests/embedder_config_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class EmbedderConfigBuilder {

void SetPlatformTaskRunner(const FlutterTaskRunnerDescription* runner);

void SetPlatformMessageCallback(
std::function<void(const FlutterPlatformMessage*)> callback);

UniqueEngine LaunchEngine();

private:
Expand Down
12 changes: 12 additions & 0 deletions shell/platform/embedder/tests/embedder_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
6 changes: 6 additions & 0 deletions shell/platform/embedder/tests/embedder_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();

Expand Down Expand Up @@ -90,6 +94,8 @@ class EmbedderContext {

void* GLGetProcAddress(const char* name);

void PlatformMessageCallback(const FlutterPlatformMessage* message);

FML_DISALLOW_COPY_AND_ASSIGN(EmbedderContext);
};

Expand Down
45 changes: 45 additions & 0 deletions shell/platform/embedder/tests/embedder_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit ea7ca98

Please sign in to comment.