-
Notifications
You must be signed in to change notification settings - Fork 390
[cronet_http] Fix: multiple Flutter engines would cause crash #1845
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
PR HealthLicense Headers ✔️
All source files should start with a license header. Unrelated files missing license headers
This check can be disabled by tagging the PR with API leaks ✔️The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.
This check can be disabled by tagging the PR with
Breaking changes
|
| Package | Change | Current Version | New Version | Needed Version | Looking good? |
|---|---|---|---|---|---|
| cronet_http | Non-Breaking | 1.6.0 | 1.6.1-wip | 1.7.0 Got "1.6.1-wip" expected >= "1.7.0" (non-breaking changes) |
This check can be disabled by tagging the PR with skip-breaking-check.
Coverage ⚠️
| File | Coverage |
|---|---|
| pkgs/cronet_http/lib/src/cronet_client.dart | 💔 Not covered |
| pkgs/cronet_http/lib/src/jni/jni_bindings.dart | 💔 Not covered |
This check for test coverage is informational (issues shown here will not fail the PR).
This check can be disabled by tagging the PR with skip-coverage-check.
Changelog Entry ✔️
| Package | Changed Files |
|---|
Changes to files need to be accounted for in their respective changelogs.
This check can be disabled by tagging the PR with skip-changelog-check.
|
@knopp There seems to be another issue where It fails when trying to test a post inside http/pkgs/http_client_conformance_tests/lib/src/isolate_test.dart Lines 16 to 17 in c8355d1
Do you have any idea why that might be? -- Update: I guess the |
|
@brianquinlan If I change the conformance test so that it creates the client itself in the main isolate and just does the POST request in another isolate, then it would work: Future<void> _testPost(Client Function() clientFactory, String host) async {
+ final client = clientFactory();
await Isolate.run(
() =>
- clientFactory()
+ client
.post(Uri.http(host, ''), body: 'Hello World!'));
}But I'm not sure if you want this behavior for cronet_http. |
|
Can we intercept background isolate creation somehow in the engine to set the engine id? Right now it is only set for the main isolate. |
At the time that I wrote this test, native pointers could not be shared between isolates. Now that they can be, I think that we should test both scenarios, i.e.:
Performing HTTP requests in a background Isolate is definitely something that people do. |
If we keep a map from isolate group ids to the engine ids, then we could fetch the right engine id using the isolate group id. Moreover, what if we just have engine id be exactly equal to the isolate group id? I assume that each engine is attached to a single isolate group anyway so this reduces the number of maps we are keeping. This way there is no need to set any engine id, instead we can just call cc @mkustermann |
|
Reading through the code, it seems the implementation does roughtly this:
Now looking through the cronet API it says: Now from a Dart perspective: The OS process can have multiple isolate groups, each of which can have multiple isolates. Flutter may start an isolate group and one particular UI isolate per flutter engine. Any isolate can spawn more isolates at runtime. When the android lifecycle system tells flutter it shuts down the current activity or UI, flutter may stop the UI isolate, but not necessarily background isolates. So isolates in a group can outlive the UI isolate, so they shouldn't depend on resources only available to the UI isolate (such as an activity context). So we'd want to avoid sharing a cronet client across isolates in an isolate group if shutting the UI isolate down will make this cronet client defunct/invalid.
@HosseinYousefi Could you explain why "engine id" matters here? Isn't this purely a question about lifecycle of android context (and other?) objects and from which isolates/threads those objects with lifecycle can be used? |
On most platforms the engineId is simply a casted pointer to engine instance. |
We're getting the application context from
Because we store a map from "engine id" to "android application context" to be able to retrieve one context per flutter engine.
Yes and we should remove the stored context from the map when That's not a problem for fetching the short-lived activity because we explicitly document that it should not be used from the other threads: This is a general |
|
(Apologies I was accidentally looking at the old code from the archived https://github.com/dart-lang/jnigen)
Well, specifically for the "global android application context" it seems there's only one per process so why not just a static global for it, initialize it once, on any second attachment call check that it's the same reference (which it should if there's only one per process) and never clear it out? See docs which says "Return the context of the single, global Application object of the current process. "
What kind of crash? |
Somehow it seems that it's not the case. Maybe the context we get from I could try getting the application context via Edit: yeah,
There are two specified in #1217 and #1842. For the second one I asked if they still face the same problem if they remove any background tasks via creating new flutter engines and they don't. I should try to reproduce this in a small example myself to make sure I'm solving the right problem here. |
If so, can you get the global one by calling Context.getApplicationContext() on the one you get from flutter? The real application context probably satisfies |
Upgraded jni and jnigen to 0.15.0. This fixes #1217 and closes #1720.