Repository navigation
☂️ Deferred Components: Build and load split AOT Android App Bundles #57617
Description
Internal: b/160378043
As detailed in dart-lang/sdk#41974, customer:money is interested in splitting their AOT code by country and by feature. Once Dart VM team provides this capability, we need changes to engine (and tooling) to be able to generate these splits and load them.
Phase 1: Install-time AOT Code Splits
This would be transparent to the app. We would load all the splits into memory when a Dart isolate gets created. This requires an engine change but no application specific API.
Phase 2: Dynamic AOT Code splits.
This would require an engine change as well which would expose a system channel to request a particular AOT split to be loaded into the isolate. It is possible that we want these asset loading that is exposed via flutter engine (FlutterLoader) to do this. FlutterLoader would access Core APIs to download the so's and then load into isolate. There's an argument to be made to extend this to any PlatformAsset; I would leave that decision to the engine team.
PS: The tooling change is lower priority from customer's point of view since we have to implement this in g3.
The following is added/tracked by @GaryQian at the top for visibility:
Tasks left TODO:
Engine:
- Support uninstalling (Rename DynamicFeature->DeferredComponent and impl uninstall DeferredComponents flutter-team-archive/engine#23224)
- Manual/System channels API for asset-only splits and uninstall (DynamicFeatureChannel MethodChannel and Install state tracking flutter-team-archive/engine#22833)
- Getter for installation state (DynamicFeatureChannel MethodChannel and Install state tracking flutter-team-archive/engine#22833)
- Improved engine DynamicFeatureManager injection (Split AOT Android Embedder and shell flutter-team-archive/engine#22179)
- Replace APKAssetResolver instead of replacing entire asset manager (AssetResolver updating in AssetManager for Dynamic features flutter-team-archive/engine#23130)
- Dart_DeferredLoadHandler implementation (Split AOT Android Embedder and shell flutter-team-archive/engine#22179)
- Core shell and embedder implementation (Split AOT Android Embedder and shell flutter-team-archive/engine#22179)
- Runtime+VM implementation (Split AOT Engine Runtime flutter-team-archive/engine#22624)
- Error handling (Add split AOT loading unit failure/error code path flutter-team-archive/engine#22857)
Framework:
- System channel for manual invocation (Add DynamicFeature system channel #71879)
- Wrapper class to expose system channel methods (DeferredComponent utility class for manual handling of Deferred Components #72895)
Tooling:
- General cleanup
- Separate into final commands (Deferred Components tooling #63773)
- Add user verification for overwrite or provide instructions for manual overwrite ([flutter_tools] Deferred components setup validator #75739)
- Improve asset packaging to no longer depend on copying into android dir (Deferred Components tooling #63773)
- Improve native lib packaging to no longer depend on copying into android dir (Deferred Components tooling #63773)
Misc:
- Finish instructions/guide (go/flutter-split-aot-instructions)
- Finalize naming, eg, what to call this feature ("Deferred Components")
Activity
xster commentedon Jun 3, 2020
Phase 2 relates to #51522
xster commentedon Jun 3, 2020
One clarification: for an mvp, do we need to alter the engine at all? Or is this purely a tooling thing?
One possibility is that we create tooling and flavors or gradle flavor-like manifests in the pubspec that lists the locale mappings. When you flutter build apk --split-by-xxx, it essentially calls build apk y times but a single filtered libapp.so gets packaged into an apk. You get y apks, each with one uniquely combined libapp.so and you upload one per locale. No engine changes.
The other possibility is that we fully adhere to the Android packaging patterns https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources and have lib-en/libflutter.so, lib-en/libcoreapp.so, lib-en/libfeatureA.so, lib-fr/libflutter.so, lib-fr/libcoreapp.so, lib-fr/libfeatureB.so etc. Engine needs to know how to load different .so.
mehmetf commentedon Jun 4, 2020
I would not go with "single filtered libapp.so" for two reasons: It really goes against the grain both externally and internally on what Android wants us to do (as you point out) and it puts the responsibility on the user to correctly configure their play store settings to deliver the right APK.
There might be a middle ground here for Install-time AOT Code Splits. Instead of "knowing which .so to load" based on user request, engine loader could eagerly "discover" and load all the .so's into Dart isolate when it starts (if there's some way of differentiating them from other so files in the APK). That takes lifecycle concerns out of the equation at least which is likely the biggest concern for this feature.
xster commentedon Jun 4, 2020
Ya, SG. I'm not quite advocating for either. Just trying to get more context on what they're asking for. Loading all .so's (and not initially creating more APIs to load on demand) SGTM too.
xster commentedon Jun 14, 2020
When we build general support for this feature, I think it makes sense to package this under the AAB "configuration APK" mechanism for the Play Store and eventually into the "dynamic feature module" mechanism.
https://developer.android.com/guide/app-bundle/dynamic-delivery
https://developer.android.com/guide/app-bundle/dynamic-delivery#dynamic_feature_manifest
Is that where g3 tooling is thinking about as well? i.e. not using APK with OOB expansions etc?
Also cc @zoeyfan as perhaps a CAB agenda item. Since these mechanisms are Play Store specific, we should get some feedback to see if there are minor adjustments we should make to make this somehow beneficial for China customers as well. i.e. are local app store mechanisms able to handle AAB uploads with module manifests specifying delayed downloads etc?
https://developer.android.com/guide/app-bundle/dynamic-delivery#customize_delivery
65 remaining items
Hixie commentedon Feb 9, 2021
Google bug is now closed, hopefully that means it won't propagate priorities anymore :-)
GaryQian commentedon Feb 10, 2021
#75739 Implements tooling setup validation.
GaryQian commentedon Mar 3, 2021
#76192 Implements build tooling such that deferred components builds are fully functional.
GaryQian commentedon Mar 5, 2021
#76192 Has landed, which brings full building and validation functionality to the tooling.
GaryQian commentedon Mar 5, 2021
Remaining work is to complete documentation and optionally land cleanup/minor feature PRs:
settings.gradleparsing and validation #76328 (settings.gradle validation)xster commentedon Mar 9, 2021
@GaryQian can you update the milestone or close this feature bug and create derivative bugs to capture the various cleanup tasks and documentation?
GaryQian commentedon Mar 16, 2021
Related: #78204
GaryQian commentedon Mar 29, 2021
https://github.com/flutter/gallery/pull/461 Implements deferred components for "crane" demo in gallery
GaryQian commentedon Mar 30, 2021
Supporting Deferred components on iOS is tracked in #79327
GaryQian commentedon Apr 8, 2021
Closing this issue. Remaining work is iOS, tracked separately.
github-actions commentedon Aug 3, 2021
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.