[IPC] Add support for specifying `Async WantsConnection` in message files
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 May 2020 21:45:47 +0000 (21:45 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 May 2020 21:45:47 +0000 (21:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=212276

Reviewed by Alex Christensen.

Augments the IPC message receiver generation script to allow for "Async WantsConnection" in `.message.in` files.
Currently, specifying this in a message causes the `connection` argument to be passed twice when handling the
IPC message. This is because normal async IPC messages without replies normally don't have the `IPC::Connection`
argument, and use the overloaded `handleMessage(Connection& connection, ...)` version of `handleMessage` when
`WantsConnection` is specified.

However, in the `Async` reply case, we already pass in the `IPC::Connection`. Instead of overloading the method
signature, we introduce a different method instead, named `handleMessageAsyncWantsConnection`, which forwards
the given `IPC::Connection` along to the member function.

Test: TestAsyncMessageWithConnection

* Platform/IPC/HandleMessage.h:
(IPC::handleMessageAsyncWantsConnection):

Add another variant of the message receiver template, for the case where the message receiver wants a connection.
This is similar to handleMessageSynchronousWantsConnection, above.

* Scripts/test-superclassMessageReceiver.cpp:
(Messages::WebPage::TestAsyncMessageWithConnection::callReply):
(Messages::WebPage::TestAsyncMessageWithConnection::cancelReply):
(Messages::WebPage::TestAsyncMessageWithConnection::send):
(WebKit::WebPage::didReceiveMessage):
* Scripts/test-superclassMessages.h:
(Messages::WebPage::TestAsyncMessageWithConnection::name):
(Messages::WebPage::TestAsyncMessageWithConnection::asyncMessageReplyName):
(Messages::WebPage::TestAsyncMessageWithConnection::TestAsyncMessageWithConnection):
(Messages::WebPage::TestAsyncMessageWithConnection::arguments const):
* Scripts/webkit/messages.py:
* Scripts/webkit/messages_unittest.py:
* Scripts/webkit/test-superclass.messages.in:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262075 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/Platform/IPC/HandleMessage.h
Source/WebKit/Scripts/test-superclassMessageReceiver.cpp
Source/WebKit/Scripts/test-superclassMessages.h
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/Scripts/webkit/messages_unittest.py
Source/WebKit/Scripts/webkit/test-superclass.messages.in

index 650e259..1fb20b6 100644 (file)
@@ -1,3 +1,42 @@
+2020-05-22  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [IPC] Add support for specifying `Async WantsConnection` in message files
+        https://bugs.webkit.org/show_bug.cgi?id=212276
+
+        Reviewed by Alex Christensen.
+
+        Augments the IPC message receiver generation script to allow for "Async WantsConnection" in `.message.in` files.
+        Currently, specifying this in a message causes the `connection` argument to be passed twice when handling the
+        IPC message. This is because normal async IPC messages without replies normally don't have the `IPC::Connection`
+        argument, and use the overloaded `handleMessage(Connection& connection, ...)` version of `handleMessage` when
+        `WantsConnection` is specified.
+
+        However, in the `Async` reply case, we already pass in the `IPC::Connection`. Instead of overloading the method
+        signature, we introduce a different method instead, named `handleMessageAsyncWantsConnection`, which forwards
+        the given `IPC::Connection` along to the member function.
+
+        Test: TestAsyncMessageWithConnection
+
+        * Platform/IPC/HandleMessage.h:
+        (IPC::handleMessageAsyncWantsConnection):
+
+        Add another variant of the message receiver template, for the case where the message receiver wants a connection.
+        This is similar to handleMessageSynchronousWantsConnection, above.
+
+        * Scripts/test-superclassMessageReceiver.cpp:
+        (Messages::WebPage::TestAsyncMessageWithConnection::callReply):
+        (Messages::WebPage::TestAsyncMessageWithConnection::cancelReply):
+        (Messages::WebPage::TestAsyncMessageWithConnection::send):
+        (WebKit::WebPage::didReceiveMessage):
+        * Scripts/test-superclassMessages.h:
+        (Messages::WebPage::TestAsyncMessageWithConnection::name):
+        (Messages::WebPage::TestAsyncMessageWithConnection::asyncMessageReplyName):
+        (Messages::WebPage::TestAsyncMessageWithConnection::TestAsyncMessageWithConnection):
+        (Messages::WebPage::TestAsyncMessageWithConnection::arguments const):
+        * Scripts/webkit/messages.py:
+        * Scripts/webkit/messages_unittest.py:
+        * Scripts/webkit/test-superclass.messages.in:
+
 2020-05-22  Tim Horton  <timothy_horton@apple.com>
 
         Excessive hang time in iOS Safari under waitForDidUpdateActivityState
index f27fb62..45c52a3 100644 (file)
@@ -183,4 +183,29 @@ void handleMessageAsync(Connection& connection, Decoder& decoder, C* object, MF
     callMemberFunction(WTFMove(*arguments), WTFMove(completionHandler), object, function);
 }
 
+template<typename T, typename C, typename MF>
+void handleMessageAsyncWantsConnection(Connection& connection, Decoder& decoder, C* object, MF function)
+{
+    Optional<uint64_t> listenerID;
+    decoder >> listenerID;
+    if (!listenerID) {
+        decoder.markInvalid();
+        return;
+    }
+
+    Optional<typename CodingType<typename T::Arguments>::Type> arguments;
+    decoder >> arguments;
+    if (!arguments) {
+        decoder.markInvalid();
+        return;
+    }
+
+    typename T::AsyncReply completionHandler = [listenerID = *listenerID, connection = makeRef(connection)] (auto&&... args) mutable {
+        auto encoder = makeUnique<Encoder>(T::asyncMessageReplyName(), 0);
+        *encoder << listenerID;
+        T::send(WTFMove(encoder), WTFMove(connection), args...);
+    };
+    callMemberFunction(connection, WTFMove(*arguments), WTFMove(completionHandler), object, function);
+}
+
 } // namespace IPC
index 17d2694..89f64c5 100644 (file)
@@ -122,6 +122,33 @@ void TestAsyncMessageWithMultipleArguments::send(std::unique_ptr<IPC::Encoder>&&
 
 #endif
 
+#if ENABLE(TEST_FEATURE)
+
+void TestAsyncMessageWithConnection::callReply(IPC::Decoder& decoder, CompletionHandler<void(bool&&)>&& completionHandler)
+{
+    Optional<bool> flag;
+    decoder >> flag;
+    if (!flag) {
+        ASSERT_NOT_REACHED();
+        cancelReply(WTFMove(completionHandler));
+        return;
+    }
+    completionHandler(WTFMove(*flag));
+}
+
+void TestAsyncMessageWithConnection::cancelReply(CompletionHandler<void(bool&&)>&& completionHandler)
+{
+    completionHandler(IPC::AsyncReplyError<bool>::create());
+}
+
+void TestAsyncMessageWithConnection::send(std::unique_ptr<IPC::Encoder>&& encoder, IPC::Connection& connection, bool flag)
+{
+    *encoder << flag;
+    connection.sendSyncReply(WTFMove(encoder));
+}
+
+#endif
+
 void TestSyncMessage::send(std::unique_ptr<IPC::Encoder>&& encoder, IPC::Connection& connection, uint8_t reply)
 {
     *encoder << reply;
@@ -165,6 +192,12 @@ void WebPage::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decod
         return;
     }
 #endif
+#if ENABLE(TEST_FEATURE)
+    if (decoder.messageName() == Messages::WebPage::TestAsyncMessageWithConnection::name()) {
+        IPC::handleMessageAsyncWantsConnection<Messages::WebPage::TestAsyncMessageWithConnection>(connection, decoder, this, &WebPage::testAsyncMessageWithConnection);
+        return;
+    }
+#endif
     WebPageBase::didReceiveMessage(connection, decoder);
 }
 
index de36457..2206b83 100644 (file)
@@ -147,6 +147,36 @@ private:
 };
 #endif
 
+#if ENABLE(TEST_FEATURE)
+class TestAsyncMessageWithConnection {
+public:
+    typedef std::tuple<const int&> Arguments;
+
+    static IPC::MessageName name() { return IPC::MessageName::WebPage_TestAsyncMessageWithConnection; }
+    static const bool isSync = false;
+
+    static void callReply(IPC::Decoder&, CompletionHandler<void(bool&&)>&&);
+    static void cancelReply(CompletionHandler<void(bool&&)>&&);
+    static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::WebPage_TestAsyncMessageWithConnectionReply; }
+    using AsyncReply = TestAsyncMessageWithConnectionAsyncReply;
+    static void send(std::unique_ptr<IPC::Encoder>&&, IPC::Connection&, bool flag);
+    using Reply = std::tuple<bool&>;
+    using ReplyArguments = std::tuple<bool>;
+    explicit TestAsyncMessageWithConnection(const int& value)
+        : m_arguments(value)
+    {
+    }
+
+    const Arguments& arguments() const
+    {
+        return m_arguments;
+    }
+
+private:
+    Arguments m_arguments;
+};
+#endif
+
 class TestSyncMessage {
 public:
     typedef std::tuple<uint32_t> Arguments;
index 19fa716..3fdd804 100644 (file)
@@ -474,7 +474,10 @@ def async_message_statement(receiver, message):
         dispatch_function_args.insert(0, 'connection')
 
     if message.has_attribute(WANTS_CONNECTION_ATTRIBUTE):
-        dispatch_function_args.insert(0, 'connection')
+        if message.has_attribute(ASYNC_ATTRIBUTE):
+            dispatch_function += 'WantsConnection'
+        else:
+            dispatch_function_args.insert(0, 'connection')
 
     result = []
     result.append('    if (decoder.messageName() == Messages::%s::%s::name()) {\n' % (receiver.name, message.name))
index 9744ef5..031a77f 100644 (file)
@@ -275,6 +275,16 @@ _expected_superclass_results = {
             'conditions': ('ENABLE(TEST_FEATURE)'),
         },
         {
+            'name': 'TestAsyncMessageWithConnection',
+            'parameters': (
+                ('int', 'value'),
+            ),
+            'reply_parameters': (
+                ('bool', 'flag'),
+            ),
+            'conditions': ('ENABLE(TEST_FEATURE)'),
+        },
+        {
             'name': 'TestSyncMessage',
             'parameters': (
                 ('uint32_t', 'param'),
index 6d59532..0a31020 100644 (file)
@@ -26,6 +26,7 @@ messages -> WebPage : WebPageBase {
     TestAsyncMessage(enum:bool WebKit::TestTwoStateEnum twoStateEnum) -> (uint64_t result) Async
     TestAsyncMessageWithNoArguments() -> () Async
     TestAsyncMessageWithMultipleArguments() -> (bool flag, uint64_t value) Async
+    TestAsyncMessageWithConnection(int value) -> (bool flag) Async WantsConnection
 #endif
     TestSyncMessage(uint32_t param) -> (uint8_t reply) Synchronous
     TestSynchronousMessage(bool value) -> (Optional<WebKit::TestClassName> optionalReply) Synchronous