-
Notifications
You must be signed in to change notification settings - Fork 6k
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
Reapply: Android background platform channels #29346
Reapply: Android background platform channels #29346
Conversation
This reverts commit 7ed91e14ccc1f5ffc4cb13d1d37e27d370c8f7cd.
70d0b71
to
697b32e
Compare
697b32e
to
f4bc527
Compare
… signature the same
f4bc527
to
4d4cc68
Compare
@dnfield I made the changes we discussed. In order to make it easier to review the change I've kept the revert of the revert as a separate commit. That represents the work that is already reviewed. |
throw new IllegalArgumentException( | ||
"Unrecognized TaskQueue, use BinaryMessenger to create your TaskQueue (ex makeBackgroundTaskQueue)."); | ||
} | ||
taskQueues.put(channel, dartMessengerTaskQueue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check if there's already a task queue assigned for this channel and throw if there is one. I'm also trying to figure out if we need a mutex around this somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it's decorated as @UiThread
...
I'm also wondering if we want to assert that this is called before setting the message handler, so that people won't get first called on the platform thread and then later called on a background thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be throwing if it is already set. This follows the same semantics for setMessageHandler. There doesn't need to be a mutex. The only datastructure accessed from 2 threads is messageHandlers
and it is a thread-safe datastructure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a test that asserts that you can call setMessageHandler first or setTaskQueue first, both work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also wondering if we want to assert that this is called before setting the message handler, so that people won't get first called on the platform thread and then later called on a background thread.
Most people are going to be using the channels, not the BinaryMessenger so it's unlikely to be a problem. I thought about this too but the semantics of forcing someone to call setTaskQueue first is ugly. I prefer to enforce something statically or just make it work and not rely on convention like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if you call setMessageHandler
first, get an onMethodCall
callback on the platform thread, then call setTaskQueue
, and get a new onMethodCall
from some other thread, and your code in onMethodCall
is not thread safe?
Even if 99% of customers will use the MethodChannel
interface, we know for sure we have some using this interface directly. We should try to make it difficult/impossible to use incorrectly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if you call setMessageHandler first, get an onMethodCall callback on the platform thread, then call setTaskQueue, and get a new onMethodCall from some other thread, and your code in onMethodCall is not thread safe?
If you call setMessageHandler, then a couple events later call setTaskQueue you will be changing the thread the handler executes on, and the user explicitly chose to do that, so it's their responsibility to make sure their handler is thread-safe. This would be consistent behavior with how the user is using the interface and is avoidable by calling setMesageHandler and setTaskQueue in the same event.
There is a draft PR that will open the plugins tree after this change lands and is rolled into master: flutter/plugins#4453 |
Would it work to have a method that sets both the That would preserve backward compatibility with existing uses of |
I think the option there would be to just add a new overloaded member called |
I did have an overloaded version like this: default void setMessageHandler(channel, handler, taskQueue) {
setMessageHandler(channel, handler);
setTaskQueue(channel, handler == null ? null : taskQueue);
} I removed it because people can override it which makes things messy since they have to call the 2 parameter variant or things break. We also don't want people to start doing verify calls onto it. It is easier just to do the minimal thing to the interface to get what we want. |
If we had another method that had overlapping semantics with setMessageHandler it confuses tests. Do we verify
We can also add unit tests to reduce the risk of them getting out of sync. I've added those, let me know if you think there is another case we should add. |
The issue is whether it should be possible to have a point in time where the message handler is registered but it isn't yet associated with the right task queue. I'd prefer that the handler and the task queue be set in one API call. Either an overload or a method with a new name would be ok. Tests that are tightly coupled to the DartMessenger implementation are going to risk breakages whenever DartMessenger changes. If this is a common scenario, then we may need to provide APIs to check whatever these tests are trying to verify (e.g. whether a plugin registered a handler for the expected channel) |
@jason-simmons @dnfield I implemented what we discussed. This is no longer a breaking change for anyone because we've provided default implementations for the new methods and maintained the signature for setMessageHandler. PTAL. |
cb010f6
to
4622a04
Compare
if (taskQueue != null) { | ||
messenger.setMessageHandler( | ||
name, handler == null ? null : new IncomingMessageHandler(handler), taskQueue); | ||
} else { | ||
messenger.setMessageHandler( | ||
name, handler == null ? null : new IncomingMessageHandler(handler)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: add a comment here (perhaps a TODO) explaining why we're doing this and that it can be simplified after the next stable roll.
@@ -42,7 +42,10 @@ | |||
* serial. | |||
*/ | |||
@UiThread | |||
TaskQueue makeBackgroundTaskQueue(); | |||
default TaskQueue makeBackgroundTaskQueue() { | |||
// TODO(aaclarke): Remove default implementation when it is safe for Google Flutter users. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please link a github issue.
@NonNull String channel, | ||
@Nullable BinaryMessageHandler handler, | ||
@Nullable TaskQueue taskQueue) { | ||
// TODO(aaclarke): Remove default implementation when it is safe for Google Flutter users. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM modulo having a github issue for the TODOs and a nitpick about adding one more todo.
Reverts #29344
That PR was reverted because the breaking change was too much. We've made it not a breaking change by overloading setMessageHandler and providing a default implementation for makeBackgroundTaskQueue.
Pre-launch Checklist
writing and running engine tests.
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.