Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@xster
Copy link
Member

@xster xster commented Sep 7, 2019

Fixes flutter/flutter#32946
Fixes flutter/flutter#33145
Fixes flutter/flutter#37195

Partially alleviates flutter/flutter#32987

Remove the call mainly because the extra granularity is error-prone boilerplate (flutter/flutter#39675, flutter/flutter#39384, flutter/flutter#39108, flutter/flutter#30332, flutter/flutter#28439) and doesn't really add any degree of control.

On a low end Android device, this means merging in the 40ms call to load the native library with the already 290ms call to create the VM. Controlling when that 40ms call happens isn't useful.

Redundant calls will still work, as will the old embedding. This just allows new code using the new embedding to omit the FlutterMain calls.

Add an AndroidJUnit in-process test in the scenario_app project. It makes sure the real engine boots on a device. Didn't hook into firebase in this PR yet. One step at a time.

Also added some supplemental docs while going through this.

* <p>
* The first {@code FlutterEngine} instance constructed per process will also load the Flutter
* native library and start a Dart VM.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want another

tag here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

* A new {@code FlutterEngine} does come with all default system channels attached.
* <p>
* The first {@code FlutterEngine} instance constructed per process will also load the Flutter
* native library and start a Dart VM.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you describe the time and memory impact of this here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's loop back to this after I write the website page for this this week-ish. I'd like to keep all these numbers in a centralized place that's easy to update if they change.

* and {@link FlutterMain#ensureInitializationComplete(io.flutter.view.Context, String[])}.
*/
public FlutterEngine(@NonNull Context context) {
FlutterMain.startInitialization(context);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these methods need to stay in FlutterMain if we're making this change? I'm not sure where a better place is yet...maybe statically in FlutterEngine, or maybe even instance methods in FlutterEngine, or possibly somewhere else. But I'd like to avoid instances of the new and improved FlutterEngine getting stuck with static dependencies on the unfortunate FlutterMain...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion. They probably shouldn't be in the FlutterEngine since that code would interact with an entirely different lifecycle as the FlutterEngine so it wouldn't be the right encapsulation. Perhaps a new io.flutter.embedding.something.FlutterLoader. Though looking at the content of FlutterMain, the encapsulation is reasonable so if we do move it, it would just be a file move.

* Once started, a {@link DartExecutor} cannot be stopped. The associated Dart code will execute
* until it completes, or until the {@link io.flutter.embedding.engine.FlutterEngine} that owns
* this {@link DartExecutor} is destroyed.
* this {@link DartExecutor} is destroyed via {@link io.flutter.embedding.engine.FlutterEngine#destroy()}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not comment on dependencies in reverse. DartExecutor does not require that it be used exclusively from a FlutterEngine, nor is it DartExecutor's business when and where a FlutterEngine destroys the DartExecutor.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds reasonable


/**
* Starts initialization of the native system.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing

tags here.


/**
* Blocks until initialization of the native system has completed.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing

tags here.

@RunWith(AndroidJUnit4.class)
public class LaunchTest {
@Test
public void testEngineLaunch() throws Throwable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please name tests based on what is being verified. E.g., engineLaunchesNormally instead of testEngineLaunch. We know that everything in here is a test, as indicated by @Test, so "test" is superfluous. With regard to "engine launch", we might choose to test a dozen different details. This test is specifically verifying a normal launch, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. Renamed smokeTestEngineLaunch

import static org.junit.Assert.fail;

@RunWith(AndroidJUnit4.class)
public class LaunchTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an end-to-end test suite, or a component test suite? If it's a component test then we said we'd name this with a ComponentTest suffix, right? Also, this strikes me more as part of an EngineComponentTest. Launching is one of the behaviors of the engine, as a component, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed this EngineLaunchE2ETest.

);
CompletableFuture<Boolean> statusReceived = new CompletableFuture<>();

engine.get().getDartExecutor().setMessageHandler(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add more comments to the lines in this test? The ones above are pretty good, but this test is doing some nuanced things. I'd prefer that we be safe and comment each step to describe what we're doing and why.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments

@xster
Copy link
Member Author

xster commented Sep 17, 2019

Any more thoughts on this one?

@xster
Copy link
Member Author

xster commented Sep 19, 2019

Discussion offline, try to create a lightweight dependency injector to make it possible to test the FlutterEngine without a real JNI backing while doing this refactor.

Also move the logic to a FlutterLoader in the new embedding package and reverse shim back into the FlutterMain APIs.

@xster
Copy link
Member Author

xster commented Sep 24, 2019

Ok, altered this PR a bit more.

Now there's a FlutterInjector lightweight dependency injector at the top level. Added some tests.

FlutterMain is hollowed out and loading and loading related utility classes are moved to io.flutter.embedding.engine.loader. Let the other existing tests use the injector mechanism to override static.

@matthew-carroll
Copy link
Contributor

Took over the PR here:
#12806

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

3 participants