Skip to content

[in_app_purchase] Write to the transactions update queue from the main thread #9068

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

edpizzi
Copy link

@edpizzi edpizzi commented Apr 14, 2025

Equeue to the channel from the main thread to avoid channel safety issues.

Background: sendTransactionUpdate can be called from the main thread, where it is safe to send messages on the onTransactionsUpdated channel. This seems to happen when the purchase code path succeeds and generates a transaction. However sendTransactionUpdate can also be called on non-main threads serving background executors, when transaction callbacks result from restoring purchases or other transactions are reported to the transaction subscription (eg. a purchase made outside of the app, or a refund is issued -- this can be triggered from XCode's StoreKit Test transaction log). In these cases, at least sometimes, an error is logged about writing to a channel on a non-platform thread (see the issue below).

Enqueue on the main thread to avoid channel thread-safety issues. This could be optimized further, but I believe this is safe.

Resolves flutter/flutter#166493

Pre-Review Checklist

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2 3

@edpizzi edpizzi requested a review from LouiseHsu as a code owner April 14, 2025 15:21
@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@edpizzi
Copy link
Author

edpizzi commented Apr 14, 2025

Hi @LouiseHsu -- I'm not able to figure out how to test this on my own. With a small change to testRestoreProductSuccess (waiting for purchaseExpectation before triggering restorePurchases), I can demonstrate a callback that comes in on a non-main thread, the error condition here. However in the unit test transactionCallbackAPI is null since we use a constructor for the plugin that does not set up a channel, so the error condition does not occur -- we don't send a message to a channel from a non-main thread, since we don't send a message at all and there is no channel.

However the reason the error is avoided is synthetic, and is specific to the unit test setup. I think testing this would require changing how the tests are structured, which I'm not sure I can take on, and either way would require maintainer guidance (i.e., why are the tests set up this way, and what is the cost / complexity of changing it to include a message channel). Even then, the success criterion would be "log message does not occur", which wouldn't cause the test to fail I don't think (unless there's a debug assert in there; I haven't seen one), so we'd have to look at the test output, unless there's a log sink we can inspect.

In any case, I think the fix is quite important, while figuring out a test strategy is less important, and I don't think it's wise to gate a fix on (unless it's disputed whether this is a crash risk). But that's just my opinion. Either way, if we gate on a test strategy, I'll require some help, and it might be better handed off to someone with domain expertise.

(There's some relevant discussion in #hackers-new in the discord as I've been trying to figure this out, but the important bits are contained here.)

@edpizzi edpizzi force-pushed the iap-storekit2-channel-thread branch from 8ecaa2c to 40e7742 Compare April 14, 2025 20:55
@edpizzi
Copy link
Author

edpizzi commented Apr 14, 2025

Ok, I implemented a testing strategy where we create a fake InAppPurchase2CallbackAPIProtocol that just asserts that it's called on the main thread, and set it on the plugin in InAppPurchase2PluginTests. Tests fail before the fix, and pass after.

@edpizzi edpizzi force-pushed the iap-storekit2-channel-thread branch 2 times, most recently from cad0e4f to 3fb7a77 Compare April 15, 2025 16:25
@LouiseHsu
Copy link
Contributor

Looks good to me! I think the failed test is flaky, Im just going to rerun it, and if it passes ill approve this :)

Copy link
Contributor

@LouiseHsu LouiseHsu left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for fixing this <3

@LouiseHsu LouiseHsu added the autosubmit Merge PR when tree becomes green via auto submit App label Apr 15, 2025
@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Apr 15, 2025
Copy link
Contributor

auto-submit bot commented Apr 15, 2025

autosubmit label was removed for flutter/packages/9068, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a flutter-hacker before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@LouiseHsu
Copy link
Contributor

oh oops. I forgot about the 2 reviewer rule. Tagging @hellohuanlin for secondary review

@LouiseHsu LouiseHsu requested a review from hellohuanlin April 15, 2025 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[in_app_purchase] StoreKit2 error logs about using a platform channel from a native thread
2 participants