Skip to content

[image_picker] Move disk accesses to background thread #4058

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

Merged
merged 4 commits into from
May 31, 2023

Conversation

JeroenWeener
Copy link
Contributor

@JeroenWeener JeroenWeener commented May 22, 2023

The plugin accesses the disk on the UI thread at several occasions as reported by flutter/flutter#91393. These instances can easily be found by running the plugin with StrictMode enabled. The occasions that are highlighted are when determining the application's cache directory and when fetching SharedPreferences.

By running method channel invocations on a background channel using Pidgeon's @TaskQueue() annotation and deferring said IO operations to the moment where they are actually needed, this PR makes sure the plugin no longer accesses the disk from the UI thread.

This PR is a follow-up to #3506

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the relevant style guides and ran the auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages repo does use dart format.)
  • I signed the CLA.
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I listed at least one issue that this PR fixes in the description above.
  • I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.
  • I updated CHANGELOG.md to add a description of the change, following repository CHANGELOG style.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

Rather than accessing the disk during initialization, the disk will now be accessed at the last possible time (which in this case means that the operation is being run on a background thread)
Copy link
Member

@gmackall gmackall left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! This mostly looks good to me, my only comment (and one it looks like @stuartmorgan raised previously), would be that it may make sense to refactor so that instead of making the calls to getCacheDir and getSharedPreferences lazy, they are still done ahead of when they are needed but on another thread. I think either way it would make sense to land this first though and have that be a follow up, so this LGTM!

@stuartmorgan have your thoughts on this changed since that initial discussion? If not I can make an issue to track. Also will hold off on autosubmit to give you time to do a secondary review.

@JeroenWeener
Copy link
Contributor Author

Thanks for the contribution! This mostly looks good to me, my only comment (and one it looks like @stuartmorgan raised previously), would be that it may make sense to refactor so that instead of making the calls to getCacheDir and getSharedPreferences lazy, they are still done ahead of when they are needed but on another thread. I think either way it would make sense to land this first though and have that be a follow up, so this LGTM!

@stuartmorgan have your thoughts on this changed since that initial discussion? If not I can make an issue to track. Also will hold off on autosubmit to give you time to do a secondary review.

Would you have any pointers on how to go about calling getCacheDir() and getSharedPreferences() ahead of when they are needed? How would calls to methods such as ImageCache.saveResult() ensure that SharedPreferences have been initialized?

@stuartmorgan-g
Copy link
Contributor

@stuartmorgan have your thoughts on this changed since that initial discussion? If not I can make an issue to track. Also will hold off on autosubmit to give you time to do a secondary review.

@JeroenWeener and I discussed this last week offline; the issue is that if we pre-initialize the cache on a different thread, it'll be on a thread that's not the same as the thread used by the platform channel system's background task handling, so going that route would mean either we'd have to do locking around the cache access, or we'd have to do all thread handling ourselves instead of using the background task annotation.

(To clarify my old comment, the reason making it lazy was listed as the non-preferred option there was that it was about making it lazy but not on a different thread, which would only solve part of the problem. This approach is lazy, but more importantly also on a different thread.)

@gmackall
Copy link
Member

@stuartmorgan have your thoughts on this changed since that initial discussion? If not I can make an issue to track. Also will hold off on autosubmit to give you time to do a secondary review.

@JeroenWeener and I discussed this last week offline; the issue is that if we pre-initialize the cache on a different thread, it'll be on a thread that's not the same as the thread used by the platform channel system's background task handling, so going that route would mean either we'd have to do locking around the cache access, or we'd have to do all thread handling ourselves instead of using the background task annotation.

(To clarify my old comment, the reason making it lazy was listed as the non-preferred option there was that it was about making it lazy but not on a different thread, which would only solve part of the problem. This approach is lazy, but more importantly also on a different thread.)

Got it, with that context it sounds to me like it would add more complexity than is worth when compared to the approach in this PR, so I retract my previous comment!

Copy link
Contributor

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

LGTM!

I wish we could test the actual behavior (i.e., that no I/O is happening on the main thread), but I don't know of any way to capture that in an integration test, and since the thread management is happening in the engine we can't do it via native unit tests.

@@ -16,11 +17,11 @@
import java.io.IOException;

class ImageResizer {
private final File externalFilesDirectory;
private final Context context;
Copy link
Contributor

Choose a reason for hiding this comment

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

It might have been simpler to keep this class as it was, and make the ImageResizer on demand instead. But this is fine too.

@stuartmorgan-g stuartmorgan-g added the autosubmit Merge PR when tree becomes green via auto submit App label May 31, 2023
@stuartmorgan-g
Copy link
Contributor

The tree status here is stale; overriding.

@stuartmorgan-g stuartmorgan-g added the emergency Override tree-status signal (land even with closed tree), combine with the autosubmit label. label May 31, 2023
@auto-submit auto-submit bot merged commit 8cef2dd into flutter:main May 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 1, 2023
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Jun 1, 2023
flutter/packages@95bb793...f0513ae

2023-05-31 [email protected] Remove legacy xcode properties and dependencies (flutter/packages#4093)
2023-05-31 [email protected] [camerax] Correct missing features list in `README` (flutter/packages#4123)
2023-05-31 [email protected] [image_picker] Move disk accesses to background thread (flutter/packages#4058)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App emergency Override tree-status signal (land even with closed tree), combine with the autosubmit label. p: image_picker platform-android
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ImagePicker should avoid making I/O operations on the platform thread
3 participants