Skip to content

Commit b831b26

Browse files
authored
Add PlatformDispatcher.engineId (flutter#163476)
Fixes flutter#163430. This PR adds `engineId` field to `PlatformDispatcher`. When provided by the engine, this can be used to retrieve the engine instance from native code. Dart code: ```dart final identifier = PlatformDispatcher.instance.engineId!; ``` macOS, iOS: ```objc FlutterEngine *engine = [FlutterEngine engineForIdentifier: identifier]; ``` Android: ```java FlutterEngine engine = FlutterEngine.engineForId(identifier); ``` Linux ```cpp FlEngine *engine = fl_engine_for_id(identifier); ``` Windows ```cpp FlutterDesktopEngineRef engine = FlutterDesktopEngineForId(identifier); ``` *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [X] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [X] I signed the [CLA]. - [X] I listed at least one issue that this PR fixes in the description above. - [X] I updated/added relevant documentation (doc comments with `///`). - [X] I added new tests to check the change I am making, or this PR is [test-exempt]. - [X] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [X] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent 600ee30 commit b831b26

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+551
-38
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2014 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+
import 'dart:convert';
6+
7+
import 'package:android_driver_extensions/extension.dart';
8+
import 'package:flutter/foundation.dart';
9+
import 'package:flutter/material.dart';
10+
import 'package:flutter_driver/driver_extension.dart';
11+
12+
import 'src/allow_list_devices.dart';
13+
14+
void main() {
15+
ensureAndroidDevice();
16+
enableFlutterDriverExtension(
17+
handler: (String? command) async {
18+
return json.encode(<String, Object?>{'engineId': PlatformDispatcher.instance.engineId});
19+
},
20+
commands: <CommandExtension>[nativeDriverCommands],
21+
);
22+
runApp(const SizedBox());
23+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2014 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+
import 'dart:convert';
6+
7+
import 'package:android_driver_extensions/native_driver.dart';
8+
import 'package:flutter_driver/flutter_driver.dart';
9+
import 'package:test/test.dart';
10+
11+
late final FlutterDriver flutterDriver;
12+
late final NativeDriver nativeDriver;
13+
14+
void main() async {
15+
setUpAll(() async {
16+
flutterDriver = await FlutterDriver.connect();
17+
nativeDriver = await AndroidNativeDriver.connect(flutterDriver);
18+
});
19+
20+
tearDownAll(() async {
21+
await nativeDriver.close();
22+
await flutterDriver.close();
23+
});
24+
25+
// TODO(matanlurey): Convert to use package:integration_test
26+
test('verify that engineId is set and works', () async {
27+
final Map<String, Object?> response =
28+
json.decode(await flutterDriver.requestData('')) as Map<String, Object?>;
29+
expect(
30+
response['engineId'],
31+
1,
32+
// Valid engine ids start at 1 to make detecting uninitialized
33+
// values easier.
34+
reason: 'engineId of first engine instance should be 1',
35+
);
36+
}, timeout: Timeout.none);
37+
}

engine/src/flutter/lib/ui/hooks.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ void _sendViewFocusEvent(int viewId, int viewFocusState, int viewFocusDirection)
6868
PlatformDispatcher.instance._sendViewFocusEvent(viewFocusEvent);
6969
}
7070

71+
@pragma('vm:entry-point')
72+
void _setEngineId(int engineId) {
73+
PlatformDispatcher.instance._engineId = engineId;
74+
}
75+
7176
@pragma('vm:entry-point')
7277
void _updateDisplays(
7378
List<int> ids,

engine/src/flutter/lib/ui/platform_dispatcher.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,13 @@ class PlatformDispatcher {
305305
_invoke1<ViewFocusEvent>(onViewFocusChange, _onViewFocusChangeZone, event);
306306
}
307307

308+
/// Opaque engine identifier for the engine running current isolate. Can be used
309+
/// in native code to retrieve the engine instance.
310+
/// The identifier is valid while the isolate is running.
311+
int? get engineId => _engineId;
312+
313+
int? _engineId;
314+
308315
// Called from the engine, via hooks.dart.
309316
//
310317
// Updates the available displays.

engine/src/flutter/lib/ui/window/platform_configuration.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ void PlatformConfiguration::DidCreateIsolate() {
4949
send_view_focus_event_.Set(
5050
tonic::DartState::Current(),
5151
Dart_GetField(library, tonic::ToDart("_sendViewFocusEvent")));
52+
set_engine_id_.Set(tonic::DartState::Current(),
53+
Dart_GetField(library, tonic::ToDart("_setEngineId")));
5254
update_window_metrics_.Set(
5355
tonic::DartState::Current(),
5456
Dart_GetField(library, tonic::ToDart("_updateWindowMetrics")));
@@ -168,6 +170,20 @@ bool PlatformConfiguration::SendFocusEvent(const ViewFocusEvent& event) {
168170
return true;
169171
}
170172

173+
bool PlatformConfiguration::SetEngineId(int64_t engine_id) {
174+
std::shared_ptr<tonic::DartState> dart_state =
175+
set_engine_id_.dart_state().lock();
176+
if (!dart_state) {
177+
return false;
178+
}
179+
tonic::DartState::Scope scope(dart_state);
180+
tonic::CheckAndHandleError(
181+
tonic::DartInvoke(set_engine_id_.Get(), {
182+
tonic::ToDart(engine_id),
183+
}));
184+
return true;
185+
}
186+
171187
bool PlatformConfiguration::UpdateViewMetrics(
172188
int64_t view_id,
173189
const ViewportMetrics& view_metrics) {

engine/src/flutter/lib/ui/window/platform_configuration.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,14 @@ class PlatformConfiguration final {
356356
/// @return Whether the focus event was sent.
357357
bool SendFocusEvent(const ViewFocusEvent& event);
358358

359+
/// @brief Sets the opaque identifier of the engine.
360+
///
361+
/// The identifier can be passed from Dart to native code to
362+
/// retrieve the engine instance.
363+
///
364+
/// @return Whether the identifier was set.
365+
bool SetEngineId(int64_t engine_id);
366+
359367
//----------------------------------------------------------------------------
360368
/// @brief Update the view metrics for the specified view.
361369
///
@@ -548,6 +556,7 @@ class PlatformConfiguration final {
548556
tonic::DartPersistentValue add_view_;
549557
tonic::DartPersistentValue remove_view_;
550558
tonic::DartPersistentValue send_view_focus_event_;
559+
tonic::DartPersistentValue set_engine_id_;
551560
tonic::DartPersistentValue update_window_metrics_;
552561
tonic::DartPersistentValue update_displays_;
553562
tonic::DartPersistentValue update_locales_;

engine/src/flutter/lib/web_ui/lib/platform_dispatcher.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ abstract class PlatformDispatcher {
3737

3838
FlutterView? get implicitView;
3939

40+
int? get engineId;
41+
4042
VoidCallback? get onMetricsChanged;
4143
set onMetricsChanged(VoidCallback? callback);
4244

engine/src/flutter/lib/web_ui/lib/src/engine/platform_dispatcher.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
140140
@override
141141
EngineFlutterWindow? get implicitView => viewManager[kImplicitViewId] as EngineFlutterWindow?;
142142

143+
@override
144+
int? get engineId => null;
145+
143146
/// A callback that is invoked whenever the platform's [devicePixelRatio],
144147
/// [physicalSize], [padding], [viewInsets], or [systemGestureInsets]
145148
/// values change, for example when the device is rotated or when the

engine/src/flutter/runtime/runtime_controller.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,8 @@ bool RuntimeController::LaunchRootIsolate(
537537
std::optional<std::string> dart_entrypoint_library,
538538
const std::vector<std::string>& dart_entrypoint_args,
539539
std::unique_ptr<IsolateConfiguration> isolate_configuration,
540-
std::shared_ptr<NativeAssetsManager> native_assets_manager) {
540+
std::shared_ptr<NativeAssetsManager> native_assets_manager,
541+
std::optional<int64_t> engine_id) {
541542
if (root_isolate_.lock()) {
542543
FML_LOG(ERROR) << "Root isolate was already running.";
543544
return false;
@@ -586,6 +587,11 @@ bool RuntimeController::LaunchRootIsolate(
586587
if (!FlushRuntimeStateToIsolate()) {
587588
FML_DLOG(ERROR) << "Could not set up initial isolate state.";
588589
}
590+
if (engine_id) {
591+
if (!platform_configuration->SetEngineId(*engine_id)) {
592+
FML_DLOG(ERROR) << "Could not set engine identifier.";
593+
}
594+
}
589595
} else {
590596
FML_DCHECK(false) << "RuntimeController created without window binding.";
591597
}

engine/src/flutter/runtime/runtime_controller.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ class RuntimeController : public PlatformConfigurationClient,
156156
/// @param[in] dart_entrypoint_args Arguments passed as a List<String>
157157
/// to Dart's entrypoint function.
158158
/// @param[in] isolate_configuration The isolate configuration
159+
/// @param[in] engine_id. Engine identifier to be passed to the
160+
/// platform dispatcher.
159161
///
160162
/// @return If the isolate could be launched and guided to the
161163
/// `DartIsolate::Phase::Running` phase.
@@ -167,7 +169,8 @@ class RuntimeController : public PlatformConfigurationClient,
167169
std::optional<std::string> dart_entrypoint_library,
168170
const std::vector<std::string>& dart_entrypoint_args,
169171
std::unique_ptr<IsolateConfiguration> isolate_configuration,
170-
std::shared_ptr<NativeAssetsManager> native_assets_manager);
172+
std::shared_ptr<NativeAssetsManager> native_assets_manager,
173+
std::optional<int64_t> engine_id);
171174

172175
//----------------------------------------------------------------------------
173176
/// @brief Clone the runtime controller. Launching an isolate with a

0 commit comments

Comments
 (0)