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

Wire up channel for restoration data #18042

Merged
merged 16 commits into from
Jun 12, 2020
Merged

Conversation

goderbauer
Copy link
Member

@goderbauer goderbauer commented Apr 29, 2020

Part of flutter/flutter#6827.

Android provides the engine with the restoration data in the Bundle given to the onCreate callback. The framework can retrieve this data via the new channel. When the framework has new restoration data to store it can send it over the channel to the engine. The engine will hold onto it until Android asks for the data by invoking the onSaveInstanceState callback.

@cbracken
Copy link
Member

/cc @jason-simmons and @GaryQian who may have thoughts on this approach.

@goderbauer
Copy link
Member Author

/cc @xster, who may also have thoughts on this.

@xster xster self-requested a review April 30, 2020 23:45
@goderbauer
Copy link
Member Author

I changed this PR to accommodate pre-cached engines (or other engines that have a different lifecycle then the activity):

  • To properly support pre-warmed engines that run dart code before they are attached to an activity and thus before we have a chance to provide them with restoration data, the RestorationChannel can be configured to delay responding to a framework request for the current restoration data until the engine has provided said data (controlled via the willProvideRestorationData on the engine).
  • The activity/fragment can enable/disable state restoration by overriding shouldRestoreAndSaveState. Cached engines have state restoration turned off by default, but this can be overridden via a setting in the intent that launched the activity.

@goderbauer goderbauer marked this pull request as ready for review June 10, 2020 17:24
@fluttergithubbot

This comment has been minimized.

@auto-assign auto-assign bot requested a review from gw280 June 10, 2020 17:25
@goderbauer
Copy link
Member Author

@xster This one is ready for another review. (I still need to add tests, though)

Copy link
Member

@xster xster left a comment

Choose a reason for hiding this comment

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

Generally LGTM. Just some nits to make sure we leave more breadcrumbs for future maintainers.

@@ -949,6 +950,17 @@ public void onFlutterUiNoLongerDisplayed() {
// no-op
}

@Override
public boolean shouldRestoreAndSaveState() {
Copy link
Member

Choose a reason for hiding this comment

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

Please document this in a doc section in the class doc

@@ -949,6 +950,17 @@ public void onFlutterUiNoLongerDisplayed() {
// no-op
}

@Override
public boolean shouldRestoreAndSaveState() {
if (getIntent().hasExtra(EXTRA_ENABLE_STATE_RESTORATION)) {
Copy link
Member

Choose a reason for hiding this comment

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

sprinkle some comments here for while some values were chosen

ensureAlive();

Bundle pluginsBundle = null;
byte[] frameworkBundle = null;
Copy link
Member

Choose a reason for hiding this comment

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

wouldn't call it bundle which is a Map<String, Parcelable> (more or less). Call it frameworkState or frameworkBundleData or something.

Copy link
Member Author

Choose a reason for hiding this comment

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

Renamed.

/** Set the restoration data from which the framework will restore its state. */
public void setRestorationData(byte[] data) {
engineHasProvidedData = true;
if (pendingResult != null) {
Copy link
Member

Choose a reason for hiding this comment

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

if one just jumps into this method here, it's not clear what this is supposed to do. Add breadcrumbs for future maintainer

bundle.putByteArray(
FRAMEWORK_RESTORATION_BUNDLE_KEY,
flutterEngine.getRestorationChannel().getRestorationData());
}
Copy link
Member

Choose a reason for hiding this comment

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

I don't really remember. We may have talked about this. Can't we clear the data now that we read this?

Copy link
Member Author

Choose a reason for hiding this comment

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

If we delete the data, engine and framework are getting out of sync which may lead to strange behavior and will make it harder to reason about restoration state. In general, framework and engine should always agree on what the current restoration state is.

Copy link
Member

Choose a reason for hiding this comment

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

Can you elaborate with a specific example? Perhaps write this down somewhere here for future archeologists too. I get the impression that we'll never run into a case where framework writes, engine reads and deletes, then the framework tries to read again? Is that 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 gave a longer answer to this on the other comment thread. In reality, the sequence of events that you describe will of course not happen. However, in reality, the only moment where we could delete the engine's copy of the restoration state is after we have handed it to the operating system. At that point, our app is moments away from getting killed anyways (thus freeing up all the memory). So why add the extra complexity of allowing framework and engine restoration state to go out of sync in this situation?

pendingResult.success(data);
pendingResult = null;
restorationData = data;
} else if (frameworkHasRequestedData) {
Copy link
Member

Choose a reason for hiding this comment

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

briefly document when this happens again, or just reference the appropriate classdoc

* <p>This should be called just prior to a hot restart. Otherwise, after the hot restart the
* state prior to the hot restart will get restored.
*/
public void clearData() {
Copy link
Member

Choose a reason for hiding this comment

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

Why not do it more frequently? There's some 2 directional complexity here but I still think it should be possible to find logical situations where this data is deterministically not useful no?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not really, as said elsewhere, the engine and framework should always be kept in sync about the restoration data. If we clear it on one side, we'd also need to clear it on the other. And hot restart is the only one that clears it on both sides.

We could potentially clear it if we know that the engine gets should down right after reading it. But the shutdown will clear it anyways, so the complexity doesn't really seem worth it.

Copy link
Member

Choose a reason for hiding this comment

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

If we clear it on one side, we'd also need to clear it on the other

what does this mean specifically? There's only memory in one place no?

Copy link
Member Author

Choose a reason for hiding this comment

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

The restoration state is duplicated on the engine and framework side because of the threading issue: The operating system will ask for the restoration state on the platform thread, the state itself is owned by the framework running on the UI thread, though. When the operating system asks for it, we can't reach into the UI thread to retrieve it (see https://docs.google.com/document/d/1KIiq5CdqnSXxQXbZIDy2Ukc-JHFyLak1JR8e2cm3eO4/edit#heading=h.xhk980xrzj8j). Therefore, we must maintain an up-to-date copy of the restoration state in the engine. The two copies are kept in sync via this channel: When the operating system provides restoration state to the engine, it sends it over the framework. When the restoration state in the framework changes, it's send back to the engine (so it can be given to the operating system when it asks for it again).

When we clear the state on one side without telling the other, we break that contract and I don't see a good reason to do it. The only place where we could delete the engine copy is after we've handed it to the operating system. In reality, the OS only asks for it moments before it kills the entire app anyway (and thus frees up the memory). So why introduce the extra complexity of sometimes engine and framework restoration state can be out of sync?

Copy link
Member

Choose a reason for hiding this comment

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

discussed offline. SG

public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
final String method = call.method;
final Object args = call.arguments;
Log.v(TAG, "Received '" + method + "' message.");
Copy link
Member

Choose a reason for hiding this comment

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

Did you want to leave this here? If so, maybe make it less generic?

if (engineHasProvidedData || !waitForRestorationData) {
result.success(restorationData);
} else {
pendingResult = result;
Copy link
Member

Choose a reason for hiding this comment

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

the names are a bit confusing. Can we rename waitForRestorationData to shouldFrameworkWaitForAsyncRestorationData and rename pendingResult to isFrameworkWaitingForRestorationData?

Copy link
Member Author

Choose a reason for hiding this comment

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

Those names sound even more confusing to me since isFrameworkWaitingForRestorationData sounds like a boolean, which it isn't. Having said that, I renamed pendingResult to pendingFrameworkRequest which should clear up the confusion.

@@ -26,7 +26,7 @@
* <p>The logical identity of the channel is given by its name. Identically named channels will
* interfere with each other's communication.
*/
public final class MethodChannel {
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, final classes cannot be mocked.

Copy link
Member

Choose a reason for hiding this comment

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

ya that's outside the scope of this PR. Left flutter/flutter#59356. Should be an "easy" fix.

@goderbauer
Copy link
Member Author

@xster All comments addressed. PTAL

@@ -63,6 +64,7 @@
* <li>Chooses Flutter's initial route.
* <li>Renders {@code Activity} transparently, if desired.
* <li>Offers hooks for subclasses to provide and configure a {@link FlutterEngine}.
* <li>Save and restore instance state, see {@code shouldRestoreAndSaveState()};
Copy link
Member

Choose a reason for hiding this comment

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

You mean {@link #shouldRestoreAndSaveState()} right?

/** Set the restoration data from which the framework will restore its state. */
public void setRestorationData(byte[] data) {
engineHasProvidedData = true;
if (pendingFrameworkRequest != null) {
Copy link
Member

Choose a reason for hiding this comment

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

ah I misread this to be a bool. Maybe "pendingFrameworkRestorationChannelRequest"?

pendingFrameworkRequest = null;
restorationData = data;
} else if (frameworkHasRequestedData) {
// If the framework has previously received the engine's restoration data, push the new data
Copy link
Member

Choose a reason for hiding this comment

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

I suppose this means the framework already asked for and have received a restoration data in the past (as opposed to the branch above). When should this happen in a non-add-to-app scenario? Or is this the use at-your-own-risk special case we talked about before? Maybe call that out in the comment for the impetuous future maintainer who might be thinking: "activity gets a bundle onCreate only once, let me delete this redundant handle".

Copy link
Member Author

Choose a reason for hiding this comment

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

Provided more context.

Copy link
Member

Choose a reason for hiding this comment

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

did you push? I don't see anything

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 can see it. Maybe reload? :P

@xster
Copy link
Member

xster commented Jun 12, 2020

A few more minor clarifications. Sorry if we already talked about this before. My memory is crapping out these days.

@xster
Copy link
Member

xster commented Jun 12, 2020

LGTM

engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 17, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 18, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 18, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 18, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 18, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 18, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 18, 2020
zljj0818 pushed a commit to zljj0818/flutter that referenced this pull request Jun 22, 2020
* 141ee78 Roll Dart SDK from 2b917f5b6a0e to 0fab083e1c2b (15 revisions) (flutter/engine#18974)

* f5ab179 Call Shell::NotifyLowMemoryWarning on Android Trim and LowMemory events (flutter/engine#18979)

* 4dabac9 Roll Fuchsia Linux SDK from 8AiUM... to ThzHh... (flutter/engine#18976)

* 50cae02 Reland: Add RAII wrapper for EGLSurface (flutter/engine#18977)

* db7f226 Include the memory header as unique_ptr is used in ASCII Trie. (flutter/engine#18978)

* b19a17d Implement an EGL resource context for the Linux shell. (flutter/engine#18918)

* ca26b75 Make Linux shell plugin constructor descriptions consistent (flutter/engine#18940)

* efd1452 Roll Skia from 9c401e7e1ace to f69e40841eb9 (11 revisions) (flutter/engine#18983)

* e5845af Put JNI functions under an interface (flutter/engine#18903)

* 1ddc6e1 Call destructor and fix check (flutter/engine#18985)

* 7f71f1d Roll Fuchsia Mac SDK from oWhyp... to gAD3P... (flutter/engine#18982)

* 74291b7 Roll Dart SDK from 0fab083e1c2b to e62b89c56d01 (10 revisions) (flutter/engine#18987)

* 2739bbf [web] Provide a hook to disable location strategy (flutter/engine#18969)

* 336d000 Roll Skia from f69e40841eb9 to 553496b66f12 (2 revisions) (flutter/engine#18992)

* b82769b Roll Skia from 553496b66f12 to 0ad37b87549b (2 revisions) (flutter/engine#18993)

* f5ca58b Roll Dart SDK from e62b89c56d01 to b0d2b97d2cd7 (4 revisions) (flutter/engine#18994)

* 2a82a08 [dart] Account for compiler api change (flutter/engine#19002)

* 369e0a9 Add ui_benchmarks (flutter/engine#18945)

* a0a92d6 Roll Skia from 0ad37b87549b to de175abede4d (1 revision) (flutter/engine#18995)

* cea5a9c Roll Dart SDK from b0d2b97d2cd7 to f043f9e5f6ea (6 revisions) (flutter/engine#18997)

* d417772 Roll Fuchsia Mac SDK from gAD3P... to Wj0yo... (flutter/engine#19001)

* 4538622 Roll Skia from de175abede4d to 32d5cfa1f35e (15 revisions) (flutter/engine#19005)

* 71fce02 Fix shift-tab not working by adding more GTK->GLFW key mappings. (flutter/engine#18988)

* 5ddc122 Fix inverted check in creating resource surface (flutter/engine#18989)

* 87d8888 Show warning if method response errors occur and error not handled. (flutter/engine#18946)

* 5171fbd Roll Skia from 32d5cfa1f35e to 21bbfc6c2dfe (5 revisions) (flutter/engine#19006)

* 4bd6aea Always send key events, even if they're used for text input. (flutter/engine#18991)

* 9f898e9 Don't process key events when the text input is not requested (flutter/engine#18990)

* 48d7091 Roll buildroot for Windows warning update (flutter/engine#19000)

* 5f37029 Roll Dart SDK from f043f9e5f6ea to f0ea02bc51f8 (22 revisions) (flutter/engine#19010)

* ac809b4 onBeginFrame JNI (flutter/engine#18866)

* e1c622b Make SKSL caching test work on Fuchsia on arm64 (flutter/engine#18572)

* 2651beb Exit before pushing a trace event when layer tree holder is empty (flutter/engine#19008)

* acf048b Remove log added for local testing (flutter/engine#19012)

* 1f3aa23 Roll Dart SDK from f0ea02bc51f8 to 0b64f5488965 (9 revisions) (flutter/engine#19013)

* 8dcc95d Roll Fuchsia Mac SDK from Wj0yo... to gR0Zc... (flutter/engine#19015)

* f6455fa Roll Dart SDK from 0b64f5488965 to 50836c171e91 (4 revisions) (flutter/engine#19017)

* b2fea9d Roll Skia from 21bbfc6c2dfe to 30212b7941d6 (6 revisions) (flutter/engine#19009)

* 0065646 Roll Skia from 30212b7941d6 to 3d6bf04366f6 (17 revisions) (flutter/engine#19020)

* 0a852d8 Revert "Call Shell::NotifyLowMemoryWarning on Android Trim and LowMemory events (flutter#18979)" (flutter/engine#19023)

* 194acdf apply null safety syntax to mobile dart:ui (flutter/engine#18933)

* b0a0e0e Roll Skia from 3d6bf04366f6 to 637838d20abd (2 revisions) (flutter/engine#19021)

* be499ab Roll Fuchsia Mac SDK from gR0Zc... to H-uAk... (flutter/engine#19022)

* 8c24c41 Roll Skia from 637838d20abd to ac16760df463 (1 revision) (flutter/engine#19025)

* 7cb7003 onEndFrame JNI (flutter/engine#18867)

* e3fdb23 [fuchsia] Add ability to configure separate data and asset dirs (flutter/engine#18858)

* 983b6e1 Call Shell::NotifyLowMemory when backgrounded/memory pressure occurs on Android (flutter/engine#19026)

* f7d241f Wire up channel for restoration data (flutter/engine#18042)

* e84d497 Fix hit testing logic in fuchsia a11y (flutter/engine#19029)

* 801559a Revert to last-known-good-rev of Dart SDK (flutter/engine#19031)
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
* 141ee78 Roll Dart SDK from 2b917f5b6a0e to 0fab083e1c2b (15 revisions) (flutter/engine#18974)

* f5ab179 Call Shell::NotifyLowMemoryWarning on Android Trim and LowMemory events (flutter/engine#18979)

* 4dabac9 Roll Fuchsia Linux SDK from 8AiUM... to ThzHh... (flutter/engine#18976)

* 50cae02 Reland: Add RAII wrapper for EGLSurface (flutter/engine#18977)

* db7f226 Include the memory header as unique_ptr is used in ASCII Trie. (flutter/engine#18978)

* b19a17d Implement an EGL resource context for the Linux shell. (flutter/engine#18918)

* ca26b75 Make Linux shell plugin constructor descriptions consistent (flutter/engine#18940)

* efd1452 Roll Skia from 9c401e7e1ace to f69e40841eb9 (11 revisions) (flutter/engine#18983)

* e5845af Put JNI functions under an interface (flutter/engine#18903)

* 1ddc6e1 Call destructor and fix check (flutter/engine#18985)

* 7f71f1d Roll Fuchsia Mac SDK from oWhyp... to gAD3P... (flutter/engine#18982)

* 74291b7 Roll Dart SDK from 0fab083e1c2b to e62b89c56d01 (10 revisions) (flutter/engine#18987)

* 2739bbf [web] Provide a hook to disable location strategy (flutter/engine#18969)

* 336d000 Roll Skia from f69e40841eb9 to 553496b66f12 (2 revisions) (flutter/engine#18992)

* b82769b Roll Skia from 553496b66f12 to 0ad37b87549b (2 revisions) (flutter/engine#18993)

* f5ca58b Roll Dart SDK from e62b89c56d01 to b0d2b97d2cd7 (4 revisions) (flutter/engine#18994)

* 2a82a08 [dart] Account for compiler api change (flutter/engine#19002)

* 369e0a9 Add ui_benchmarks (flutter/engine#18945)

* a0a92d6 Roll Skia from 0ad37b87549b to de175abede4d (1 revision) (flutter/engine#18995)

* cea5a9c Roll Dart SDK from b0d2b97d2cd7 to f043f9e5f6ea (6 revisions) (flutter/engine#18997)

* d417772 Roll Fuchsia Mac SDK from gAD3P... to Wj0yo... (flutter/engine#19001)

* 4538622 Roll Skia from de175abede4d to 32d5cfa1f35e (15 revisions) (flutter/engine#19005)

* 71fce02 Fix shift-tab not working by adding more GTK->GLFW key mappings. (flutter/engine#18988)

* 5ddc122 Fix inverted check in creating resource surface (flutter/engine#18989)

* 87d8888 Show warning if method response errors occur and error not handled. (flutter/engine#18946)

* 5171fbd Roll Skia from 32d5cfa1f35e to 21bbfc6c2dfe (5 revisions) (flutter/engine#19006)

* 4bd6aea Always send key events, even if they're used for text input. (flutter/engine#18991)

* 9f898e9 Don't process key events when the text input is not requested (flutter/engine#18990)

* 48d7091 Roll buildroot for Windows warning update (flutter/engine#19000)

* 5f37029 Roll Dart SDK from f043f9e5f6ea to f0ea02bc51f8 (22 revisions) (flutter/engine#19010)

* ac809b4 onBeginFrame JNI (flutter/engine#18866)

* e1c622b Make SKSL caching test work on Fuchsia on arm64 (flutter/engine#18572)

* 2651beb Exit before pushing a trace event when layer tree holder is empty (flutter/engine#19008)

* acf048b Remove log added for local testing (flutter/engine#19012)

* 1f3aa23 Roll Dart SDK from f0ea02bc51f8 to 0b64f5488965 (9 revisions) (flutter/engine#19013)

* 8dcc95d Roll Fuchsia Mac SDK from Wj0yo... to gR0Zc... (flutter/engine#19015)

* f6455fa Roll Dart SDK from 0b64f5488965 to 50836c171e91 (4 revisions) (flutter/engine#19017)

* b2fea9d Roll Skia from 21bbfc6c2dfe to 30212b7941d6 (6 revisions) (flutter/engine#19009)

* 0065646 Roll Skia from 30212b7941d6 to 3d6bf04366f6 (17 revisions) (flutter/engine#19020)

* 0a852d8 Revert "Call Shell::NotifyLowMemoryWarning on Android Trim and LowMemory events (flutter#18979)" (flutter/engine#19023)

* 194acdf apply null safety syntax to mobile dart:ui (flutter/engine#18933)

* b0a0e0e Roll Skia from 3d6bf04366f6 to 637838d20abd (2 revisions) (flutter/engine#19021)

* be499ab Roll Fuchsia Mac SDK from gR0Zc... to H-uAk... (flutter/engine#19022)

* 8c24c41 Roll Skia from 637838d20abd to ac16760df463 (1 revision) (flutter/engine#19025)

* 7cb7003 onEndFrame JNI (flutter/engine#18867)

* e3fdb23 [fuchsia] Add ability to configure separate data and asset dirs (flutter/engine#18858)

* 983b6e1 Call Shell::NotifyLowMemory when backgrounded/memory pressure occurs on Android (flutter/engine#19026)

* f7d241f Wire up channel for restoration data (flutter/engine#18042)

* e84d497 Fix hit testing logic in fuchsia a11y (flutter/engine#19029)

* 801559a Revert to last-known-good-rev of Dart SDK (flutter/engine#19031)
@goderbauer goderbauer mentioned this pull request Jan 7, 2021
13 tasks
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants