diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-05-09 14:22:11 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2016-05-09 15:11:45 +0000 |
commit | 2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c (patch) | |
tree | e75f511546c5fd1a173e87c1f9fb11d7ac8d1af3 /chromium/ipc | |
parent | a4f3d46271c57e8155ba912df46a05559d14726e (diff) | |
download | qtwebengine-chromium-2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c.tar.gz |
BASELINE: Update Chromium to 51.0.2704.41
Also adds in all smaller components by reversing logic for exclusion.
Change-Id: Ibf90b506e7da088ea2f65dcf23f2b0992c504422
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'chromium/ipc')
97 files changed, 3097 insertions, 3516 deletions
diff --git a/chromium/ipc/BUILD.gn b/chromium/ipc/BUILD.gn index 1dddc13484c..c3d3bb45b10 100644 --- a/chromium/ipc/BUILD.gn +++ b/chromium/ipc/BUILD.gn @@ -26,6 +26,7 @@ component("ipc") { "brokerable_attachment.h", "brokerable_attachment_mac.cc", "brokerable_attachment_win.cc", + "export_template.h", "handle_attachment_win.cc", "handle_attachment_win.h", "handle_win.cc", @@ -65,6 +66,8 @@ component("ipc") { "ipc_message_generator.h", "ipc_message_macros.h", "ipc_message_start.h", + "ipc_message_templates.h", + "ipc_message_templates_impl.h", "ipc_message_utils.cc", "ipc_message_utils.h", "ipc_platform_file.cc", @@ -88,6 +91,8 @@ component("ipc") { "message_filter.h", "message_filter_router.cc", "message_filter_router.h", + "message_router.cc", + "message_router.h", "param_traits_log_macros.h", "param_traits_macros.h", "param_traits_read_macros.h", @@ -144,13 +149,6 @@ source_set("param_traits") { ] } -group("ipc_tests_run") { - testonly = true - deps = [ - ":ipc_tests", - ] -} - test("ipc_tests") { sources = [ "attachment_broker_mac_unittest.cc", @@ -179,18 +177,16 @@ test("ipc_tests") { sources -= [ "unix_domain_socket_util_unittest.cc" ] } + if (is_android) { + # These multiprocess tests don't work on Android. + sources -= [ "ipc_channel_unittest.cc" ] + } + # TODO(brettw) hook up Android testing. #if (is_android && gtest_target_type == "shared_library") { # deps += "/testing/android/native_test.gyp:native_testNative_code" #} - # TODO(brettw) hook up tcmalloc to this target. - #if (is_posix && !is_mac && !is_android) { - # if (use_allocator!="none") { - # deps += "/base/allocator" - # } - #} - deps = [ ":ipc", ":test_support", @@ -213,12 +209,6 @@ test("ipc_perftests") { # deps += "/testing/android/native_test.gyp:native_testNative_code" #} - # TODO(brettw) hook up tcmalloc to this target. - #if (is_posix && !is_mac && !is_android) { - # if (use_allocator!="none") { - # deps += "//base/allocator" - # } - #} deps = [ ":ipc", ":test_support", diff --git a/chromium/ipc/OWNERS b/chromium/ipc/OWNERS index 54320464d06..76fd94129fb 100644 --- a/chromium/ipc/OWNERS +++ b/chromium/ipc/OWNERS @@ -1,4 +1,3 @@ -agl@chromium.org cpu@chromium.org darin@chromium.org jam@chromium.org diff --git a/chromium/ipc/attachment_broker.cc b/chromium/ipc/attachment_broker.cc index 50e3e2d9ae7..f53a4cf0123 100644 --- a/chromium/ipc/attachment_broker.cc +++ b/chromium/ipc/attachment_broker.cc @@ -18,9 +18,6 @@ namespace IPC { // static void AttachmentBroker::SetGlobal(AttachmentBroker* broker) { - CHECK(!g_attachment_broker || !broker) - << "Global attachment broker address: " << broker - << ". New attachment broker address: " << broker; g_attachment_broker = broker; } @@ -61,6 +58,16 @@ void AttachmentBroker::AddObserver( info.runner = runner; info.unique_id = ++last_unique_id_; observers_.push_back(info); + + // Give the observer a chance to handle attachments that arrived while the + // observer was handling the message that caused it to register, but our + // mutex was not yet locked. + for (const auto& attachment : attachments_) { + info.runner->PostTask( + FROM_HERE, + base::Bind(&AttachmentBroker::NotifyObserver, base::Unretained(this), + info.unique_id, attachment->GetIdentifier())); + } } } @@ -74,7 +81,9 @@ void AttachmentBroker::RemoveObserver(AttachmentBroker::Observer* observer) { observers_.erase(it); } -void AttachmentBroker::RegisterCommunicationChannel(Endpoint* endpoint) { +void AttachmentBroker::RegisterCommunicationChannel( + Endpoint* endpoint, + scoped_refptr<base::SingleThreadTaskRunner> runner) { NOTREACHED(); } @@ -82,6 +91,20 @@ void AttachmentBroker::DeregisterCommunicationChannel(Endpoint* endpoint) { NOTREACHED(); } +void AttachmentBroker::RegisterBrokerCommunicationChannel(Endpoint* endpoint) { + NOTREACHED(); +} + +void AttachmentBroker::DeregisterBrokerCommunicationChannel( + Endpoint* endpoint) { + NOTREACHED(); +} + +bool AttachmentBroker::IsPrivilegedBroker() { + NOTREACHED(); + return false; +} + void AttachmentBroker::HandleReceivedAttachment( const scoped_refptr<BrokerableAttachment>& attachment) { { @@ -127,6 +150,8 @@ void AttachmentBroker::NotifyObserver( } AttachmentBroker::ObserverInfo::ObserverInfo() {} +AttachmentBroker::ObserverInfo::ObserverInfo(const ObserverInfo& other) = + default; AttachmentBroker::ObserverInfo::~ObserverInfo() {} } // namespace IPC diff --git a/chromium/ipc/attachment_broker.h b/chromium/ipc/attachment_broker.h index 4cf1ab5de58..70383edf713 100644 --- a/chromium/ipc/attachment_broker.h +++ b/chromium/ipc/attachment_broker.h @@ -27,6 +27,7 @@ namespace base { class SequencedTaskRunner; +class SingleThreadTaskRunner; }; namespace IPC { @@ -94,9 +95,21 @@ class IPC_EXPORT AttachmentBroker : public Listener { // communicates attachment information with the broker process. In the broker // process, these channels must be registered and deregistered with the // Attachment Broker as they are created and destroyed. - virtual void RegisterCommunicationChannel(Endpoint* endpoint); + // + // Invocations of Send() on |endpoint| will occur on thread bound to |runner|. + virtual void RegisterCommunicationChannel( + Endpoint* endpoint, + scoped_refptr<base::SingleThreadTaskRunner> runner); virtual void DeregisterCommunicationChannel(Endpoint* endpoint); + // In each unprivileged process, exactly one channel should be used to + // communicate brokerable attachments with the broker process. + virtual void RegisterBrokerCommunicationChannel(Endpoint* endpoint); + virtual void DeregisterBrokerCommunicationChannel(Endpoint* endpoint); + + // True if and only if this broker is privileged. + virtual bool IsPrivilegedBroker(); + protected: using AttachmentVector = std::vector<scoped_refptr<BrokerableAttachment>>; @@ -134,6 +147,7 @@ class IPC_EXPORT AttachmentBroker : public Listener { struct ObserverInfo { ObserverInfo(); + ObserverInfo(const ObserverInfo& other); ~ObserverInfo(); Observer* observer; diff --git a/chromium/ipc/attachment_broker_mac_unittest.cc b/chromium/ipc/attachment_broker_mac_unittest.cc index bf994b77db2..b569706ef8b 100644 --- a/chromium/ipc/attachment_broker_mac_unittest.cc +++ b/chromium/ipc/attachment_broker_mac_unittest.cc @@ -9,12 +9,15 @@ #include <stddef.h> #include <sys/mman.h> +#include <tuple> + #include "base/command_line.h" #include "base/files/file_util.h" #include "base/files/scoped_file.h" #include "base/files/scoped_temp_dir.h" #include "base/mac/mac_util.h" #include "base/mac/mach_logging.h" +#include "base/memory/free_deleter.h" #include "base/memory/scoped_ptr.h" #include "base/memory/shared_memory.h" #include "base/strings/string_number_conversions.h" @@ -111,7 +114,7 @@ base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1( return base::SharedMemoryHandle(); } - return base::get<1>(p); + return std::get<1>(p); } // |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns @@ -132,8 +135,8 @@ bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message, return false; } - *handle1 = base::get<0>(p); - *handle2 = base::get<1>(p); + *handle1 = std::get<0>(p); + *handle2 = std::get<1>(p); return true; } @@ -419,6 +422,12 @@ class IPCAttachmentBrokerMacTest : public IPCTestBase { // Setup shared between tests. void CommonSetUp(const char* name) { + PreConnectSetUp(name); + PostConnectSetUp(); + } + + // All of setup before the channel is connected. + void PreConnectSetUp(const char* name) { Init(name); MachPreForkSetUp(); @@ -427,7 +436,11 @@ class IPCAttachmentBrokerMacTest : public IPCTestBase { broker_->AddObserver(&observer_, task_runner()); CreateChannel(&proxy_listener_); - broker_->DesignateBrokerCommunicationChannel(channel()); + broker_->RegisterBrokerCommunicationChannel(channel()); + } + + // All of setup including the connection and everything after. + void PostConnectSetUp() { ASSERT_TRUE(ConnectChannel()); ASSERT_TRUE(StartClient()); @@ -561,7 +574,7 @@ int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient( IPCTestBase::GetChannelName(channel_name), &listener)); - globals->broker->RegisterCommunicationChannel(channel.get()); + globals->broker->RegisterCommunicationChannel(channel.get(), nullptr); CHECK(channel->Connect()); globals->initial_resident_size = GetResidentSize(); @@ -595,10 +608,6 @@ int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, // it. The SharedMemoryHandle is sent to the privileged process using Chrome // IPC. The privileged process checks that it received the same memory region. TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("SendSharedMemoryHandle"); SendMessage1(kDataBuffer1); @@ -621,10 +630,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) { // Similar to SendSharedMemoryHandle, but sends a very long shared memory // region. TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("SendSharedMemoryHandleLong"); std::string buffer(1 << 23, 'a'); @@ -649,10 +654,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) { // Similar to SendSharedMemoryHandle, but sends two different shared memory // regions in two messages. TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle"); SendMessage1(kDataBuffer1); @@ -685,10 +686,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) { // Similar to SendSharedMemoryHandle, but sends the same shared memory region in // two messages. TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("SendTwoMessagesSameSharedMemoryHandle"); { @@ -735,10 +732,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) { // memory regions. TEST_F(IPCAttachmentBrokerMacTest, SendOneMessageWithTwoDifferentSharedMemoryHandles) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles"); { @@ -782,10 +775,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN( // same memory region twice. TEST_F(IPCAttachmentBrokerMacTest, SendOneMessageWithTwoSameSharedMemoryHandles) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles"); { @@ -825,10 +814,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN( // Sends one message with two Posix FDs and two Mach ports. TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); base::FilePath fp1, fp2; @@ -868,16 +853,16 @@ void SendPosixFDAndMachPortCallback(IPC::Sender* sender, return; } - base::SharedMemoryHandle handle1 = base::get<1>(p); - base::SharedMemoryHandle handle2 = base::get<3>(p); + base::SharedMemoryHandle handle1 = std::get<1>(p); + base::SharedMemoryHandle handle2 = std::get<3>(p); bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) && CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2); if (!success1) LOG(ERROR) << "SharedMemoryHandles have wrong contents."; bool success2 = - CheckContentsOfFileDescriptor(base::get<0>(p), kDataBuffer3) && - CheckContentsOfFileDescriptor(base::get<2>(p), kDataBuffer4); + CheckContentsOfFileDescriptor(std::get<0>(p), kDataBuffer3) && + CheckContentsOfFileDescriptor(std::get<2>(p), kDataBuffer4); if (!success2) LOG(ERROR) << "FileDescriptors have wrong contents."; @@ -893,16 +878,12 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) { // process. This is an unrealistic scenario, but simulates an unprivileged // process sending an attachment to another unprivileged process. TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - SetBroker(new MockBroker); - CommonSetUp("SendSharedMemoryHandleToSelf"); - + PreConnectSetUp("SendSharedMemoryHandleToSelf"); // Technically, the channel is an endpoint, but we need the proxy listener to // receive the messages so that it can quit the message loop. channel()->SetAttachmentBrokerEndpoint(false); + PostConnectSetUp(); get_proxy_listener()->set_listener(get_broker()); { @@ -955,10 +936,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) { // Similar to SendSharedMemoryHandle, but uses a ChannelProxy instead of a // Channel. TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - Init("SendSharedMemoryHandleChannelProxy"); MachPreForkSetUp(); @@ -971,8 +948,12 @@ TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) { options.message_loop_type = base::MessageLoop::TYPE_IO; thread->StartWithOptions(options); - CreateChannelProxy(get_proxy_listener(), thread->task_runner().get()); - get_broker()->DesignateBrokerCommunicationChannel(channel_proxy()); + set_channel_proxy(std::unique_ptr<IPC::ChannelProxy>(new IPC::ChannelProxy( + get_proxy_listener(), thread->task_runner().get()))); + get_broker()->RegisterBrokerCommunicationChannel(channel_proxy()); + channel_proxy()->Init( + CreateChannelFactory(GetTestChannelHandle(), thread->task_runner().get()), + true); ASSERT_TRUE(StartClient()); @@ -1011,10 +992,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleChannelProxy) { // Similar to SendSharedMemoryHandle, but first makes a copy of the handle using // ShareToProcess(). TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("ShareToProcess"); { @@ -1045,10 +1022,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareToProcess) { // Similar to ShareToProcess, but instead shares the memory object only with // read permissions. TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("ShareReadOnlyToProcess"); { @@ -1098,16 +1071,12 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) { // Similar to SendSharedMemoryHandleToSelf, but the child process pretends to // not have the task port for the parent process. TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelfDelayedPort) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - SetBroker(new MockBroker); - CommonSetUp("SendSharedMemoryHandleToSelfDelayedPort"); - + PreConnectSetUp("SendSharedMemoryHandleToSelfDelayedPort"); // Technically, the channel is an endpoint, but we need the proxy listener to // receive the messages so that it can quit the message loop. channel()->SetAttachmentBrokerEndpoint(false); + PostConnectSetUp(); get_proxy_listener()->set_listener(get_broker()); { @@ -1198,10 +1167,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) { // resident memory at different points in time, and that measurement is // non-deterministic. TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("MemoryUsageLargeMessage"); std::string test_string(g_large_message_size, 'a'); @@ -1252,10 +1217,6 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) { // resident memory at different points in time, and that measurement is // non-deterministic. TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - CommonSetUp("MemoryUsageManyMessages"); for (int i = 0; i < g_large_message_count; ++i) { diff --git a/chromium/ipc/attachment_broker_privileged.cc b/chromium/ipc/attachment_broker_privileged.cc index 85c1ac949cd..9f41892f721 100644 --- a/chromium/ipc/attachment_broker_privileged.cc +++ b/chromium/ipc/attachment_broker_privileged.cc @@ -6,7 +6,9 @@ #include <algorithm> +#include "base/bind.h" #include "base/lazy_instance.h" +#include "base/location.h" #include "base/metrics/histogram_macros.h" #include "build/build_config.h" #include "ipc/ipc_endpoint.h" @@ -67,9 +69,7 @@ scoped_ptr<AttachmentBrokerPrivileged> CreateBroker() { // the global broker. class AttachmentBrokerMakeOnce { public: - AttachmentBrokerMakeOnce() { - attachment_broker_.reset(CreateBroker().release()); - } + AttachmentBrokerMakeOnce() : attachment_broker_(CreateBroker()) {} private: scoped_ptr<IPC::AttachmentBrokerPrivileged> attachment_broker_; @@ -112,31 +112,57 @@ void AttachmentBrokerPrivileged::CreateBrokerForSingleProcessTests() { } void AttachmentBrokerPrivileged::RegisterCommunicationChannel( - Endpoint* endpoint) { + Endpoint* endpoint, + scoped_refptr<base::SingleThreadTaskRunner> runner) { base::AutoLock auto_lock(*get_lock()); endpoint->SetAttachmentBrokerEndpoint(true); - auto it = std::find(endpoints_.begin(), endpoints_.end(), endpoint); + auto it = std::find_if(endpoints_.begin(), endpoints_.end(), + [endpoint](const EndpointRunnerPair& pair) { + return pair.first == endpoint; + }); DCHECK(endpoints_.end() == it); - endpoints_.push_back(endpoint); + endpoints_.push_back(std::make_pair(endpoint, runner)); } void AttachmentBrokerPrivileged::DeregisterCommunicationChannel( Endpoint* endpoint) { base::AutoLock auto_lock(*get_lock()); - auto it = std::find(endpoints_.begin(), endpoints_.end(), endpoint); + auto it = std::find_if(endpoints_.begin(), endpoints_.end(), + [endpoint](const EndpointRunnerPair& pair) { + return pair.first == endpoint; + }); if (it != endpoints_.end()) endpoints_.erase(it); } -Sender* AttachmentBrokerPrivileged::GetSenderWithProcessId(base::ProcessId id) { +bool AttachmentBrokerPrivileged::IsPrivilegedBroker() { + return true; +} + +AttachmentBrokerPrivileged::EndpointRunnerPair +AttachmentBrokerPrivileged::GetSenderWithProcessId(base::ProcessId id) { get_lock()->AssertAcquired(); auto it = std::find_if(endpoints_.begin(), endpoints_.end(), - [id](Endpoint* c) { return c->GetPeerPID() == id; }); + [id](const EndpointRunnerPair& pair) { + return pair.first->GetPeerPID() == id; + }); if (it == endpoints_.end()) - return nullptr; + return std::make_pair(nullptr, nullptr); return *it; } +void AttachmentBrokerPrivileged::SendMessageToEndpoint(EndpointRunnerPair pair, + Message* message) { + if (!pair.second || pair.second->BelongsToCurrentThread()) { + pair.first->Send(message); + } else { + pair.second->PostTask( + FROM_HERE, + base::Bind(&AttachmentBrokerPrivileged::SendMessageToEndpoint, + base::Unretained(this), pair, message)); + } +} + void AttachmentBrokerPrivileged::LogError(UMAError error) { UMA_HISTOGRAM_ENUMERATION( "IPC.AttachmentBrokerPrivileged.BrokerAttachmentError", error, ERROR_MAX); diff --git a/chromium/ipc/attachment_broker_privileged.h b/chromium/ipc/attachment_broker_privileged.h index 686bb9d282a..1fff37f387b 100644 --- a/chromium/ipc/attachment_broker_privileged.h +++ b/chromium/ipc/attachment_broker_privileged.h @@ -5,9 +5,11 @@ #ifndef IPC_ATTACHMENT_BROKER_PRIVILEGED_H_ #define IPC_ATTACHMENT_BROKER_PRIVILEGED_H_ +#include <utility> #include <vector> #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "build/build_config.h" #include "ipc/attachment_broker.h" @@ -48,16 +50,26 @@ class IPC_EXPORT AttachmentBrokerPrivileged : public IPC::AttachmentBroker { static void CreateBrokerForSingleProcessTests(); // AttachmentBroker overrides. - void RegisterCommunicationChannel(Endpoint* endpoint) override; + void RegisterCommunicationChannel( + Endpoint* endpoint, + scoped_refptr<base::SingleThreadTaskRunner> runner) override; void DeregisterCommunicationChannel(Endpoint* endpoint) override; + bool IsPrivilegedBroker() override; protected: + using EndpointRunnerPair = + std::pair<Endpoint*, scoped_refptr<base::SingleThreadTaskRunner>>; + // Returns the sender whose peer's process id is |id|. // Returns nullptr if no sender is found. // The lock returned by get_lock() must already be acquired before calling // this method. The return value is only guaranteed to be valid while the lock // is held. - Sender* GetSenderWithProcessId(base::ProcessId id); + EndpointRunnerPair GetSenderWithProcessId(base::ProcessId id); + + // Sends a message to the endpoint, dispatching onto another thread if + // necessary. + void SendMessageToEndpoint(EndpointRunnerPair pair, Message* message); // Errors that can be reported by subclasses. // These match tools/metrics/histograms.xml. @@ -104,7 +116,9 @@ class IPC_EXPORT AttachmentBrokerPrivileged : public IPC::AttachmentBroker { void LogError(UMAError error); private: - std::vector<Endpoint*> endpoints_; + // A vector of Endpoints, and the SingleThreadTaskRunner that should be used + // to invoke Send() on each Endpoint. + std::vector<EndpointRunnerPair> endpoints_; DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerPrivileged); }; diff --git a/chromium/ipc/attachment_broker_privileged_mac.cc b/chromium/ipc/attachment_broker_privileged_mac.cc index c5bed27c68d..fdf4715b348 100644 --- a/chromium/ipc/attachment_broker_privileged_mac.cc +++ b/chromium/ipc/attachment_broker_privileged_mac.cc @@ -6,6 +6,9 @@ #include <stdint.h> +#include <tuple> + +#include "base/mac/mach_port_util.h" #include "base/mac/scoped_mach_port.h" #include "base/memory/shared_memory.h" #include "base/process/port_provider_mac.h" @@ -16,49 +19,6 @@ #include "ipc/ipc_channel.h" #include "ipc/mach_port_attachment_mac.h" -namespace { - -// Struct for sending a complex Mach message. -struct MachSendComplexMessage { - mach_msg_header_t header; - mach_msg_body_t body; - mach_msg_port_descriptor_t data; -}; - -// Sends a Mach port to |endpoint|. Assumes that |endpoint| is a send once -// right. Takes ownership of |endpoint|. -kern_return_t SendMachPort(mach_port_t endpoint, - mach_port_t port_to_send, - int disposition) { - MachSendComplexMessage send_msg; - send_msg.header.msgh_bits = - MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0) | MACH_MSGH_BITS_COMPLEX; - send_msg.header.msgh_size = sizeof(send_msg); - send_msg.header.msgh_remote_port = endpoint; - send_msg.header.msgh_local_port = MACH_PORT_NULL; - send_msg.header.msgh_reserved = 0; - send_msg.header.msgh_id = 0; - send_msg.body.msgh_descriptor_count = 1; - send_msg.data.name = port_to_send; - send_msg.data.disposition = disposition; - send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR; - - kern_return_t kr = - mach_msg(&send_msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, - send_msg.header.msgh_size, - 0, // receive limit - MACH_PORT_NULL, // receive name - 0, // timeout - MACH_PORT_NULL); // notification port - - if (kr != KERN_SUCCESS) - mach_port_deallocate(mach_task_self(), endpoint); - - return kr; -} - -} // namespace - namespace IPC { AttachmentBrokerPrivilegedMac::AttachmentBrokerPrivilegedMac( @@ -183,7 +143,7 @@ void AttachmentBrokerPrivilegedMac::OnDuplicateMachPort( return; } IPC::internal::MachPortAttachmentMac::WireFormat wire_format = - base::get<0>(param); + std::get<0>(param); if (wire_format.destination_process == base::kNullProcessId) { LogError(NO_DESTINATION); @@ -214,8 +174,9 @@ bool AttachmentBrokerPrivilegedMac::RouteWireFormatToAnother( // Another process is the destination. base::ProcessId dest = wire_format.destination_process; base::AutoLock auto_lock(*get_lock()); - Sender* sender = GetSenderWithProcessId(dest); - if (!sender) { + AttachmentBrokerPrivileged::EndpointRunnerPair pair = + GetSenderWithProcessId(dest); + if (!pair.first) { // Assuming that this message was not sent from a malicious process, the // channel endpoint that would have received this message will block // forever. @@ -226,65 +187,11 @@ bool AttachmentBrokerPrivilegedMac::RouteWireFormatToAnother( } LogError(DESTINATION_FOUND); - sender->Send(new AttachmentBrokerMsg_MachPortHasBeenDuplicated(wire_format)); + SendMessageToEndpoint( + pair, new AttachmentBrokerMsg_MachPortHasBeenDuplicated(wire_format)); return true; } -mach_port_name_t AttachmentBrokerPrivilegedMac::CreateIntermediateMachPort( - mach_port_t task_port, - base::mac::ScopedMachSendRight port_to_insert) { - DCHECK_NE(mach_task_self(), task_port); - DCHECK_NE(static_cast<mach_port_name_t>(MACH_PORT_NULL), task_port); - - // Make a port with receive rights in the destination task. - mach_port_name_t endpoint; - kern_return_t kr = - mach_port_allocate(task_port, MACH_PORT_RIGHT_RECEIVE, &endpoint); - if (kr != KERN_SUCCESS) { - LogError(ERROR_MAKE_RECEIVE_PORT); - return MACH_PORT_NULL; - } - - // Change its message queue limit so that it accepts one message. - mach_port_limits limits = {}; - limits.mpl_qlimit = 1; - kr = mach_port_set_attributes(task_port, endpoint, MACH_PORT_LIMITS_INFO, - reinterpret_cast<mach_port_info_t>(&limits), - MACH_PORT_LIMITS_INFO_COUNT); - if (kr != KERN_SUCCESS) { - LogError(ERROR_SET_ATTRIBUTES); - mach_port_deallocate(task_port, endpoint); - return MACH_PORT_NULL; - } - - // Get a send right. - mach_port_t send_once_right; - mach_msg_type_name_t send_right_type; - kr = - mach_port_extract_right(task_port, endpoint, MACH_MSG_TYPE_MAKE_SEND_ONCE, - &send_once_right, &send_right_type); - if (kr != KERN_SUCCESS) { - LogError(ERROR_EXTRACT_DEST_RIGHT); - mach_port_deallocate(task_port, endpoint); - return MACH_PORT_NULL; - } - DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND_ONCE), - send_right_type); - - // This call takes ownership of |send_once_right|. - kr = SendMachPort( - send_once_right, port_to_insert.get(), MACH_MSG_TYPE_COPY_SEND); - if (kr != KERN_SUCCESS) { - LogError(ERROR_SEND_MACH_PORT); - mach_port_deallocate(task_port, endpoint); - return MACH_PORT_NULL; - } - - // Endpoint is intentionally leaked into the destination task. An IPC must be - // sent to the destination task so that it can clean up this port. - return endpoint; -} - base::mac::ScopedMachSendRight AttachmentBrokerPrivilegedMac::ExtractNamedRight( mach_port_t task_port, mach_port_name_t named_right) { @@ -324,7 +231,9 @@ void AttachmentBrokerPrivilegedMac::SendPrecursorsForProcess( if (!to_self) { base::AutoLock auto_lock(*get_lock()); - if (!GetSenderWithProcessId(pid)) { + AttachmentBrokerPrivileged::EndpointRunnerPair pair = + GetSenderWithProcessId(pid); + if (!pair.first) { // If there is no sender, then the destination process is no longer // running, or never existed to begin with. LogError(DESTINATION_NOT_FOUND); @@ -365,8 +274,28 @@ bool AttachmentBrokerPrivilegedMac::SendPrecursor( base::mac::ScopedMachSendRight port_to_insert = precursor->TakePort(); mach_port_name_t intermediate_port = MACH_PORT_NULL; if (port_to_insert.get() != MACH_PORT_NULL) { - intermediate_port = CreateIntermediateMachPort( - task_port, base::mac::ScopedMachSendRight(port_to_insert.release())); + base::MachCreateError error_code; + intermediate_port = base::CreateIntermediateMachPort( + task_port, base::mac::ScopedMachSendRight(port_to_insert.release()), + &error_code); + if (intermediate_port == MACH_PORT_NULL) { + UMAError uma_error; + switch (error_code) { + case base::MachCreateError::ERROR_MAKE_RECEIVE_PORT: + uma_error = ERROR_MAKE_RECEIVE_PORT; + break; + case base::MachCreateError::ERROR_SET_ATTRIBUTES: + uma_error = ERROR_SET_ATTRIBUTES; + break; + case base::MachCreateError::ERROR_EXTRACT_DEST_RIGHT: + uma_error = ERROR_EXTRACT_DEST_RIGHT; + break; + case base::MachCreateError::ERROR_SEND_MACH_PORT: + uma_error = ERROR_SEND_MACH_PORT; + break; + } + LogError(uma_error); + } } return RouteWireFormatToAnother( CopyWireFormat(wire_format, intermediate_port)); @@ -394,7 +323,9 @@ void AttachmentBrokerPrivilegedMac::ProcessExtractorsForProcess( { base::AutoLock auto_lock(*get_lock()); - if (!GetSenderWithProcessId(pid)) { + AttachmentBrokerPrivileged::EndpointRunnerPair pair = + GetSenderWithProcessId(pid); + if (!pair.first) { // If there is no sender, then the source process is no longer running. LogError(ERROR_SOURCE_NOT_FOUND); delete it->second; diff --git a/chromium/ipc/attachment_broker_privileged_mac.h b/chromium/ipc/attachment_broker_privileged_mac.h index c13cba01ead..0393fe1d91a 100644 --- a/chromium/ipc/attachment_broker_privileged_mac.h +++ b/chromium/ipc/attachment_broker_privileged_mac.h @@ -141,17 +141,6 @@ class IPC_EXPORT AttachmentBrokerPrivilegedMac MachPortWireFormat DuplicateMachPort(const MachPortWireFormat& wire_format, base::ProcessId source_process); - // |task_port| is the task port of another process. - // |port_to_insert| must be a send right in the current task's name space. - // Creates an intermediate Mach port in |pid| and sends |port_to_insert| as a - // mach_msg to the intermediate Mach port. - // Returns the intermediate port on success, and MACH_PORT_NULL on failure. - // This method takes ownership of |port_to_insert|. On success, ownership is - // passed to the intermediate Mach port. - mach_port_name_t CreateIntermediateMachPort( - mach_port_t task_port, - base::mac::ScopedMachSendRight port_to_insert); - // Extracts a copy of the send right to |named_right| from |task_port|. // Returns MACH_PORT_NULL on error. base::mac::ScopedMachSendRight ExtractNamedRight( diff --git a/chromium/ipc/attachment_broker_privileged_mac_unittest.cc b/chromium/ipc/attachment_broker_privileged_mac_unittest.cc index 15aecb66211..53981943bba 100644 --- a/chromium/ipc/attachment_broker_privileged_mac_unittest.cc +++ b/chromium/ipc/attachment_broker_privileged_mac_unittest.cc @@ -14,6 +14,7 @@ #include "base/command_line.h" #include "base/mac/mac_util.h" #include "base/mac/mach_logging.h" +#include "base/mac/mach_port_util.h" #include "base/mac/scoped_mach_port.h" #include "base/macros.h" #include "base/memory/shared_memory.h" @@ -181,10 +182,6 @@ class AttachmentBrokerPrivilegedMacMultiProcessTest // The attachment broker inserts a right for a memory object into the // destination task. TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertRight) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - SetUpChild("InsertRightClient"); mach_msg_type_number_t original_name_count = GetActiveNameCount(); IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_); @@ -198,9 +195,10 @@ TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertRight) { // port. IncrementMachRefCount(shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND); - mach_port_name_t inserted_memory_object = broker.CreateIntermediateMachPort( - client_task_port_.get(), base::mac::ScopedMachSendRight( - shared_memory->handle().GetMemoryObject())); + mach_port_name_t inserted_memory_object = base::CreateIntermediateMachPort( + client_task_port_.get(), + base::mac::ScopedMachSendRight(shared_memory->handle().GetMemoryObject()), + nullptr); EXPECT_NE(inserted_memory_object, static_cast<mach_port_name_t>(MACH_PORT_NULL)); SendUInt32(client_port_.get(), inserted_memory_object); @@ -248,10 +246,6 @@ MULTIPROCESS_TEST_MAIN(InsertRightClient) { // The attachment broker inserts the right for a memory object into the // destination task twice. TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertSameRightTwice) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - SetUpChild("InsertSameRightTwiceClient"); mach_msg_type_number_t original_name_count = GetActiveNameCount(); IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_); @@ -266,10 +260,11 @@ TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertSameRightTwice) { for (int i = 0; i < 2; ++i) { IncrementMachRefCount(shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND); - mach_port_name_t inserted_memory_object = broker.CreateIntermediateMachPort( + mach_port_name_t inserted_memory_object = base::CreateIntermediateMachPort( client_task_port_.get(), base::mac::ScopedMachSendRight( - shared_memory->handle().GetMemoryObject())); + shared_memory->handle().GetMemoryObject()), + nullptr); EXPECT_NE(inserted_memory_object, static_cast<mach_port_name_t>(MACH_PORT_NULL)); SendUInt32(client_port_.get(), inserted_memory_object); @@ -344,10 +339,6 @@ MULTIPROCESS_TEST_MAIN(InsertSameRightTwiceClient) { // The attachment broker inserts the rights for two memory objects into the // destination task. TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertTwoRights) { - // Mach-based SharedMemory isn't support on OSX 10.6. - if (base::mac::IsOSSnowLeopard()) - return; - SetUpChild("InsertTwoRightsClient"); mach_msg_type_number_t original_name_count = GetActiveNameCount(); IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_); @@ -362,10 +353,11 @@ TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertTwoRights) { // port. IncrementMachRefCount(shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND); - mach_port_name_t inserted_memory_object = broker.CreateIntermediateMachPort( + mach_port_name_t inserted_memory_object = base::CreateIntermediateMachPort( client_task_port_.get(), base::mac::ScopedMachSendRight( - shared_memory->handle().GetMemoryObject())); + shared_memory->handle().GetMemoryObject()), + nullptr); EXPECT_NE(inserted_memory_object, static_cast<mach_port_name_t>(MACH_PORT_NULL)); SendUInt32(client_port_.get(), inserted_memory_object); diff --git a/chromium/ipc/attachment_broker_privileged_win.cc b/chromium/ipc/attachment_broker_privileged_win.cc index c749a09c980..06470128df9 100644 --- a/chromium/ipc/attachment_broker_privileged_win.cc +++ b/chromium/ipc/attachment_broker_privileged_win.cc @@ -6,6 +6,8 @@ #include <windows.h> +#include <tuple> + #include "base/process/process.h" #include "ipc/attachment_broker_messages.h" #include "ipc/brokerable_attachment.h" @@ -59,7 +61,7 @@ void AttachmentBrokerPrivilegedWin::OnDuplicateWinHandle( if (!AttachmentBrokerMsg_DuplicateWinHandle::Read(&message, ¶m)) return; IPC::internal::HandleAttachmentWin::WireFormat wire_format = - base::get<0>(param); + std::get<0>(param); if (wire_format.destination_process == base::kNullProcessId) { LogError(NO_DESTINATION); @@ -84,8 +86,9 @@ void AttachmentBrokerPrivilegedWin::RouteDuplicatedHandle( // Another process is the destination. base::ProcessId dest = wire_format.destination_process; base::AutoLock auto_lock(*get_lock()); - Sender* sender = GetSenderWithProcessId(dest); - if (!sender) { + AttachmentBrokerPrivileged::EndpointRunnerPair pair = + GetSenderWithProcessId(dest); + if (!pair.first) { // Assuming that this message was not sent from a malicious process, the // channel endpoint that would have received this message will block // forever. @@ -96,7 +99,8 @@ void AttachmentBrokerPrivilegedWin::RouteDuplicatedHandle( } LogError(DESTINATION_FOUND); - sender->Send(new AttachmentBrokerMsg_WinHandleHasBeenDuplicated(wire_format)); + SendMessageToEndpoint( + pair, new AttachmentBrokerMsg_WinHandleHasBeenDuplicated(wire_format)); } AttachmentBrokerPrivilegedWin::HandleWireFormat diff --git a/chromium/ipc/attachment_broker_privileged_win_unittest.cc b/chromium/ipc/attachment_broker_privileged_win_unittest.cc index b25214d9d95..36a7c68e175 100644 --- a/chromium/ipc/attachment_broker_privileged_win_unittest.cc +++ b/chromium/ipc/attachment_broker_privileged_win_unittest.cc @@ -6,6 +6,8 @@ #include <windows.h> +#include <tuple> + #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" @@ -76,7 +78,7 @@ ScopedHandle GetHandleFromTestHandleWinMsg(const IPC::Message& message) { return ScopedHandle(nullptr); } - IPC::HandleWin handle_win = base::get<1>(p); + IPC::HandleWin handle_win = std::get<1>(p); return ScopedHandle(handle_win.get_handle()); } @@ -97,7 +99,7 @@ scoped_ptr<base::SharedMemory> GetSharedMemoryFromSharedMemoryHandleMsg1( return nullptr; } - base::SharedMemoryHandle handle = base::get<0>(p); + base::SharedMemoryHandle handle = std::get<0>(p); scoped_ptr<base::SharedMemory> shared_memory( new base::SharedMemory(handle, false)); @@ -123,9 +125,9 @@ bool GetHandleFromTestTwoHandleWinMsg(const IPC::Message& message, return false; } - IPC::HandleWin handle_win = base::get<0>(p); + IPC::HandleWin handle_win = std::get<0>(p); *h1 = handle_win.get_handle(); - handle_win = base::get<1>(p); + handle_win = std::get<1>(p); *h2 = handle_win.get_handle(); return true; } @@ -263,11 +265,21 @@ class IPCAttachmentBrokerPrivilegedWinTest : public IPCTestBase { } void CommonSetUp() { + PreConnectSetUp(); + PostConnectSetUp(); + } + + // All of setup before the channel is connected. + void PreConnectSetUp() { if (!broker_.get()) set_broker(new IPC::AttachmentBrokerUnprivilegedWin); broker_->AddObserver(&observer_, task_runner()); CreateChannel(&proxy_listener_); - broker_->DesignateBrokerCommunicationChannel(channel()); + broker_->RegisterBrokerCommunicationChannel(channel()); + } + + // All of setup including the connection and everything after. + void PostConnectSetUp() { ASSERT_TRUE(ConnectChannel()); ASSERT_TRUE(StartClient()); @@ -388,10 +400,12 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleToSelf) { Init("SendHandleToSelf"); set_broker(new MockBroker); - CommonSetUp(); + + PreConnectSetUp(); // Technically, the channel is an endpoint, but we need the proxy listener to // receive the messages so that it can quit the message loop. channel()->SetAttachmentBrokerEndpoint(false); + PostConnectSetUp(); get_proxy_listener()->set_listener(get_broker()); HANDLE h = CreateTempFile(); @@ -470,7 +484,7 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleTwice) { // An unprivileged process makes a shared memory region and sends it to the // privileged process. -TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendSharedMemoryHandle) { +TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendSharedMemoryHandle) { Init("SendSharedMemoryHandle"); CommonSetUp(); @@ -504,7 +518,7 @@ int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, IPC::AttachmentBrokerPrivilegedWin broker; scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient( IPCTestBase::GetChannelName(channel_name), &listener)); - broker.RegisterCommunicationChannel(channel.get()); + broker.RegisterCommunicationChannel(channel.get(), nullptr); CHECK(channel->Connect()); while (true) { diff --git a/chromium/ipc/attachment_broker_unprivileged.cc b/chromium/ipc/attachment_broker_unprivileged.cc index 9286a890057..c1e4c4ac7c1 100644 --- a/chromium/ipc/attachment_broker_unprivileged.cc +++ b/chromium/ipc/attachment_broker_unprivileged.cc @@ -4,6 +4,7 @@ #include "ipc/attachment_broker_unprivileged.h" +#include "base/lazy_instance.h" #include "base/metrics/histogram_macros.h" #include "build/build_config.h" #include "ipc/ipc_channel.h" @@ -19,18 +20,15 @@ namespace IPC { -AttachmentBrokerUnprivileged::AttachmentBrokerUnprivileged() - : sender_(nullptr) { - IPC::AttachmentBroker::SetGlobal(this); -} - -AttachmentBrokerUnprivileged::~AttachmentBrokerUnprivileged() { - IPC::AttachmentBroker::SetGlobal(nullptr); -} +namespace { -// static -scoped_ptr<AttachmentBrokerUnprivileged> -AttachmentBrokerUnprivileged::CreateBroker() { +// On platforms that support attachment brokering, returns a new instance of +// a platform-specific attachment broker. Otherwise returns |nullptr|. +// The caller takes ownership of the newly created instance, and is +// responsible for ensuring that the attachment broker lives longer than +// every IPC::Channel. The new instance automatically registers itself as the +// global attachment broker. +scoped_ptr<AttachmentBrokerUnprivileged> CreateBroker() { #if defined(OS_WIN) return scoped_ptr<AttachmentBrokerUnprivileged>( new IPC::AttachmentBrokerUnprivilegedWin); @@ -42,7 +40,42 @@ AttachmentBrokerUnprivileged::CreateBroker() { #endif } -void AttachmentBrokerUnprivileged::DesignateBrokerCommunicationChannel( +// This class is wrapped in a LazyInstance to ensure that its constructor is +// only called once. The constructor creates an attachment broker and sets it as +// the global broker. +class AttachmentBrokerMakeOnce { + public: + AttachmentBrokerMakeOnce() { + // Single process tests can cause an attachment broker to already exist. + if (AttachmentBroker::GetGlobal()) + return; + attachment_broker_ = CreateBroker(); + } + + private: + scoped_ptr<IPC::AttachmentBrokerUnprivileged> attachment_broker_; +}; + +base::LazyInstance<AttachmentBrokerMakeOnce>::Leaky + g_attachment_broker_make_once = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +AttachmentBrokerUnprivileged::AttachmentBrokerUnprivileged() + : sender_(nullptr) { + IPC::AttachmentBroker::SetGlobal(this); +} + +AttachmentBrokerUnprivileged::~AttachmentBrokerUnprivileged() { + IPC::AttachmentBroker::SetGlobal(nullptr); +} + +// static +void AttachmentBrokerUnprivileged::CreateBrokerIfNeeded() { + g_attachment_broker_make_once.Get(); +} + +void AttachmentBrokerUnprivileged::RegisterBrokerCommunicationChannel( Endpoint* endpoint) { DCHECK(endpoint); DCHECK(!sender_); @@ -50,6 +83,17 @@ void AttachmentBrokerUnprivileged::DesignateBrokerCommunicationChannel( endpoint->SetAttachmentBrokerEndpoint(true); } +void AttachmentBrokerUnprivileged::DeregisterBrokerCommunicationChannel( + Endpoint* endpoint) { + DCHECK(endpoint); + DCHECK_EQ(endpoint, sender_); + sender_ = nullptr; +} + +bool AttachmentBrokerUnprivileged::IsPrivilegedBroker() { + return false; +} + void AttachmentBrokerUnprivileged::LogError(UMAError error) { UMA_HISTOGRAM_ENUMERATION( "IPC.AttachmentBrokerUnprivileged.BrokerAttachmentError", error, diff --git a/chromium/ipc/attachment_broker_unprivileged.h b/chromium/ipc/attachment_broker_unprivileged.h index b572ff8266a..f6d520de6e3 100644 --- a/chromium/ipc/attachment_broker_unprivileged.h +++ b/chromium/ipc/attachment_broker_unprivileged.h @@ -22,17 +22,15 @@ class IPC_EXPORT AttachmentBrokerUnprivileged : public IPC::AttachmentBroker { AttachmentBrokerUnprivileged(); ~AttachmentBrokerUnprivileged() override; - // On platforms that support attachment brokering, returns a new instance of - // a platform-specific attachment broker. Otherwise returns |nullptr|. - // The caller takes ownership of the newly created instance, and is - // responsible for ensuring that the attachment broker lives longer than - // every IPC::Channel. The new instance automatically registers itself as the - // global attachment broker. - static scoped_ptr<AttachmentBrokerUnprivileged> CreateBroker(); + // If there is no global attachment broker, makes a new + // AttachmentBrokerUnprivileged and sets it as the global attachment broker. + // This method is thread safe. + static void CreateBrokerIfNeeded(); - // In each unprivileged process, exactly one channel should be used to - // communicate brokerable attachments with the broker process. - void DesignateBrokerCommunicationChannel(Endpoint* endpoint); + // AttachmentBroker: + void RegisterBrokerCommunicationChannel(Endpoint* endpoint) override; + void DeregisterBrokerCommunicationChannel(Endpoint* endpoint) override; + bool IsPrivilegedBroker() override; protected: IPC::Sender* get_sender() { return sender_; } diff --git a/chromium/ipc/attachment_broker_unprivileged_mac.cc b/chromium/ipc/attachment_broker_unprivileged_mac.cc index 4e766887d9a..4f37698cdf2 100644 --- a/chromium/ipc/attachment_broker_unprivileged_mac.cc +++ b/chromium/ipc/attachment_broker_unprivileged_mac.cc @@ -6,6 +6,7 @@ #include <mach/mach.h> +#include "base/mac/mach_port_util.h" #include "base/mac/scoped_mach_port.h" #include "base/process/process.h" #include "ipc/attachment_broker_messages.h" @@ -13,36 +14,6 @@ #include "ipc/ipc_sender.h" #include "ipc/mach_port_attachment_mac.h" -namespace { - -// Struct for receiving a complex message. -struct MachReceiveComplexMessage { - mach_msg_header_t header; - mach_msg_body_t body; - mach_msg_port_descriptor_t data; - mach_msg_trailer_t trailer; -}; - -// Receives a Mach port from |port_to_listen_on|, which should have exactly one -// queued message. Returns |MACH_PORT_NULL| on any error. -base::mac::ScopedMachSendRight ReceiveMachPort(mach_port_t port_to_listen_on) { - MachReceiveComplexMessage recv_msg; - mach_msg_header_t* recv_hdr = &recv_msg.header; - recv_hdr->msgh_local_port = port_to_listen_on; - recv_hdr->msgh_size = sizeof(recv_msg); - - kern_return_t kr = - mach_msg(recv_hdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, - recv_hdr->msgh_size, port_to_listen_on, 0, MACH_PORT_NULL); - if (kr != KERN_SUCCESS) - return base::mac::ScopedMachSendRight(MACH_PORT_NULL); - if (recv_msg.header.msgh_id != 0) - return base::mac::ScopedMachSendRight(MACH_PORT_NULL); - return base::mac::ScopedMachSendRight(recv_msg.data.name); -} - -} // namespace - namespace IPC { AttachmentBrokerUnprivilegedMac::AttachmentBrokerUnprivilegedMac() {} @@ -93,7 +64,7 @@ void AttachmentBrokerUnprivilegedMac::OnMachPortHasBeenDuplicated( base::mac::ScopedMachReceiveRight message_port(wire_format.mach_port); base::mac::ScopedMachSendRight memory_object( - ReceiveMachPort(message_port.get())); + base::ReceiveMachPort(message_port.get())); LogError(memory_object.get() == MACH_PORT_NULL ? ERR_RECEIVE_MACH_MESSAGE : SUCCESS); diff --git a/chromium/ipc/export_template.h b/chromium/ipc/export_template.h new file mode 100644 index 00000000000..e743e1936f7 --- /dev/null +++ b/chromium/ipc/export_template.h @@ -0,0 +1,163 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IPC_EXPORT_TEMPLATE_H_ +#define IPC_EXPORT_TEMPLATE_H_ + +// Synopsis +// +// This header provides macros for using FOO_EXPORT macros with explicit +// template instantiation declarations and definitions. +// Generally, the FOO_EXPORT macros are used at declarations, +// and GCC requires them to be used at explicit instantiation declarations, +// but MSVC requires __declspec(dllexport) to be used at the explicit +// instantiation definitions instead. + +// Usage +// +// In a header file, write: +// +// extern template class EXPORT_TEMPLATE_DECLARE(FOO_EXPORT) foo<bar>; +// +// In a source file, write: +// +// template class EXPORT_TEMPLATE_DEFINE(FOO_EXPORT) foo<bar>; + +// Implementation notes +// +// The implementation of this header uses some subtle macro semantics to +// detect what the provided FOO_EXPORT value was defined as and then +// to dispatch to appropriate macro definitions. Unfortunately, +// MSVC's C preprocessor is rather non-compliant and requires special +// care to make it work. +// +// Issue 1. +// +// #define F(x) +// F() +// +// MSVC emits warning C4003 ("not enough actual parameters for macro +// 'F'), even though it's a valid macro invocation. This affects the +// macros below that take just an "export" parameter, because export +// may be empty. +// +// As a workaround, we can add a dummy parameter and arguments: +// +// #define F(x,_) +// F(,) +// +// Issue 2. +// +// #define F(x) G##x +// #define Gj() ok +// F(j()) +// +// The correct replacement for "F(j())" is "ok", but MSVC replaces it +// with "Gj()". As a workaround, we can pass the result to an +// identity macro to force MSVC to look for replacements again. (This +// is why EXPORT_TEMPLATE_STYLE_3 exists.) + +#define EXPORT_TEMPLATE_DECLARE(export) \ + EXPORT_TEMPLATE_INVOKE(DECLARE, EXPORT_TEMPLATE_STYLE(export, ), export) +#define EXPORT_TEMPLATE_DEFINE(export) \ + EXPORT_TEMPLATE_INVOKE(DEFINE, EXPORT_TEMPLATE_STYLE(export, ), export) + +// INVOKE is an internal helper macro to perform parameter replacements +// and token pasting to chain invoke another macro. E.g., +// EXPORT_TEMPLATE_INVOKE(DECLARE, DEFAULT, FOO_EXPORT) +// will export to call +// EXPORT_TEMPLATE_DECLARE_DEFAULT(FOO_EXPORT, ) +// (but with FOO_EXPORT expanded too). +#define EXPORT_TEMPLATE_INVOKE(which, style, export) \ + EXPORT_TEMPLATE_INVOKE_2(which, style, export) +#define EXPORT_TEMPLATE_INVOKE_2(which, style, export) \ + EXPORT_TEMPLATE_##which##_##style(export, ) + +// Default style is to apply the FOO_EXPORT macro at declaration sites. +#define EXPORT_TEMPLATE_DECLARE_DEFAULT(export, _) export +#define EXPORT_TEMPLATE_DEFINE_DEFAULT(export, _) + +// The "MSVC hack" style is used when FOO_EXPORT is defined +// as __declspec(dllexport), which MSVC requires to be used at +// definition sites instead. +#define EXPORT_TEMPLATE_DECLARE_MSVC_HACK(export, _) +#define EXPORT_TEMPLATE_DEFINE_MSVC_HACK(export, _) export + +// EXPORT_TEMPLATE_STYLE is an internal helper macro that identifies which +// export style needs to be used for the provided FOO_EXPORT macro definition. +// "", "__attribute__(...)", and "__declspec(dllimport)" are mapped +// to "DEFAULT"; while "__declspec(dllexport)" is mapped to "MSVC_HACK". +// +// It's implemented with token pasting to transform the __attribute__ and +// __declspec annotations into macro invocations. E.g., if FOO_EXPORT is +// defined as "__declspec(dllimport)", it undergoes the following sequence of +// macro substitutions: +// EXPORT_TEMPLATE_STYLE(FOO_EXPORT, ) +// EXPORT_TEMPLATE_STYLE_2(__declspec(dllimport), ) +// EXPORT_TEMPLATE_STYLE_3(EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport)) +// EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport) +// EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport +// DEFAULT +#define EXPORT_TEMPLATE_STYLE(export, _) EXPORT_TEMPLATE_STYLE_2(export, ) +#define EXPORT_TEMPLATE_STYLE_2(export, _) \ + EXPORT_TEMPLATE_STYLE_3( \ + EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA##export) +#define EXPORT_TEMPLATE_STYLE_3(style) style + +// Internal helper macros for EXPORT_TEMPLATE_STYLE. +// +// XXX: C++ reserves all identifiers containing "__" for the implementation, +// but "__attribute__" and "__declspec" already contain "__" and the token-paste +// operator can only add characters; not remove them. To minimize the risk of +// conflict with implementations, we include "foj3FJo5StF0OvIzl7oMxA" (a random +// 128-bit string, encoded in Base64) in the macro name. +#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA DEFAULT +#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__attribute__(...) \ + DEFAULT +#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__declspec(arg) \ + EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_##arg + +// Internal helper macros for EXPORT_TEMPLATE_STYLE. +#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllexport MSVC_HACK +#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport DEFAULT + +// Sanity checks. +// +// EXPORT_TEMPLATE_TEST uses the same macro invocation pattern as +// EXPORT_TEMPLATE_DECLARE and EXPORT_TEMPLATE_DEFINE do to check that they're +// working correctly. When they're working correctly, the sequence of macro +// replacements should go something like: +// +// EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport)); +// +// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT, +// EXPORT_TEMPLATE_STYLE(__declspec(dllimport), ), +// __declspec(dllimport)), "__declspec(dllimport)"); +// +// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT, +// DEFAULT, __declspec(dllimport)), "__declspec(dllimport)"); +// +// static_assert(EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT( +// __declspec(dllimport)), "__declspec(dllimport)"); +// +// static_assert(true, "__declspec(dllimport)"); +// +// When they're not working correctly, a syntax error should occur instead. +#define EXPORT_TEMPLATE_TEST(want, export) \ + static_assert(EXPORT_TEMPLATE_INVOKE( \ + TEST_##want, EXPORT_TEMPLATE_STYLE(export, ), export), \ + #export) +#define EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(...) true +#define EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK(...) true + +EXPORT_TEMPLATE_TEST(DEFAULT, ); +EXPORT_TEMPLATE_TEST(DEFAULT, __attribute__((visibility("default")))); +EXPORT_TEMPLATE_TEST(MSVC_HACK, __declspec(dllexport)); +EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport)); + +#undef EXPORT_TEMPLATE_TEST +#undef EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT +#undef EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK + +#endif // IPC_EXPORT_TEMPLATE_H_ diff --git a/chromium/ipc/handle_attachment_win.cc b/chromium/ipc/handle_attachment_win.cc index 39c4ef78c7f..cb6a7bacfc2 100644 --- a/chromium/ipc/handle_attachment_win.cc +++ b/chromium/ipc/handle_attachment_win.cc @@ -24,6 +24,10 @@ HandleAttachmentWin::HandleAttachmentWin(const HANDLE& handle, } } +HandleAttachmentWin::HandleAttachmentWin(const HANDLE& handle, + FromWire from_wire) + : handle_(handle), permissions_(HandleWin::INVALID), owns_handle_(true) {} + HandleAttachmentWin::HandleAttachmentWin(const WireFormat& wire_format) : BrokerableAttachment(wire_format.attachment_id), handle_(LongToHandle(wire_format.handle)), diff --git a/chromium/ipc/handle_attachment_win.h b/chromium/ipc/handle_attachment_win.h index 5e04bdb3626..ff0ce91a851 100644 --- a/chromium/ipc/handle_attachment_win.h +++ b/chromium/ipc/handle_attachment_win.h @@ -58,6 +58,13 @@ class IPC_EXPORT HandleAttachmentWin : public BrokerableAttachment { // result. Should only be called by the sender of a Chrome IPC message. HandleAttachmentWin(const HANDLE& handle, HandleWin::Permissions permissions); + enum FromWire { + FROM_WIRE, + }; + // This constructor takes ownership of |handle|. Should only be called by the + // receiver of a Chrome IPC message. + HandleAttachmentWin(const HANDLE& handle, FromWire from_wire); + // This constructor takes ownership of |wire_format.handle| without making a // copy. Should only be called by the receiver of a Chrome IPC message. explicit HandleAttachmentWin(const WireFormat& wire_format); diff --git a/chromium/ipc/handle_win.cc b/chromium/ipc/handle_win.cc index f964c832057..60fa54c7cd1 100644 --- a/chromium/ipc/handle_win.cc +++ b/chromium/ipc/handle_win.cc @@ -21,7 +21,7 @@ HandleWin::HandleWin(const HANDLE& handle, Permissions permissions) : handle_(handle), permissions_(permissions) {} // static -void ParamTraits<HandleWin>::Write(Message* m, const param_type& p) { +void ParamTraits<HandleWin>::Write(base::Pickle* m, const param_type& p) { scoped_refptr<IPC::internal::HandleAttachmentWin> attachment( new IPC::internal::HandleAttachmentWin(p.get_handle(), p.get_permissions())); @@ -30,16 +30,18 @@ void ParamTraits<HandleWin>::Write(Message* m, const param_type& p) { } // static -bool ParamTraits<HandleWin>::Read(const Message* m, +bool ParamTraits<HandleWin>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - scoped_refptr<MessageAttachment> attachment; - if (!m->ReadAttachment(iter, &attachment)) + scoped_refptr<base::Pickle::Attachment> base_attachment; + if (!m->ReadAttachment(iter, &base_attachment)) return false; + MessageAttachment* attachment = + static_cast<MessageAttachment*>(base_attachment.get()); if (attachment->GetType() != MessageAttachment::TYPE_BROKERABLE_ATTACHMENT) return false; BrokerableAttachment* brokerable_attachment = - static_cast<BrokerableAttachment*>(attachment.get()); + static_cast<BrokerableAttachment*>(attachment); if (brokerable_attachment->GetBrokerableType() != BrokerableAttachment::WIN_HANDLE) { return false; diff --git a/chromium/ipc/handle_win.h b/chromium/ipc/handle_win.h index 38cddae10b1..2fb5b5415ac 100644 --- a/chromium/ipc/handle_win.h +++ b/chromium/ipc/handle_win.h @@ -13,6 +13,7 @@ #include "ipc/ipc_param_traits.h" namespace base { +class Pickle; class PickleIterator; } // namespace base @@ -56,8 +57,10 @@ class IPC_EXPORT HandleWin { template <> struct IPC_EXPORT ParamTraits<HandleWin> { typedef HandleWin param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* p); static void Log(const param_type& p, std::string* l); }; diff --git a/chromium/ipc/ipc.gyp b/chromium/ipc/ipc.gyp index 05b99895112..b78bbf1674b 100644 --- a/chromium/ipc/ipc.gyp +++ b/chromium/ipc/ipc.gyp @@ -81,19 +81,14 @@ ], }], ['OS == "android"', { + 'sources!': [ + # These multiprocess tests don't work on Android. + 'ipc_channel_unittest.cc', + ], 'dependencies': [ '../testing/android/native_test.gyp:native_test_native_code', ], }], - ['os_posix == 1 and OS != "mac" and OS != "android"', { - 'conditions': [ - ['use_allocator!="none"', { - 'dependencies': [ - '../base/allocator/allocator.gyp:allocator', - ], - }], - ], - }] ], }, { @@ -123,15 +118,6 @@ '../testing/android/native_test.gyp:native_test_native_code', ], }], - ['os_posix == 1 and OS != "mac" and OS != "android"', { - 'conditions': [ - ['use_allocator!="none"', { - 'dependencies': [ - '../base/allocator/allocator.gyp:allocator', - ], - }], - ], - }] ], }, { diff --git a/chromium/ipc/ipc.gypi b/chromium/ipc/ipc.gypi index dbd2099e4c3..da570d230bf 100644 --- a/chromium/ipc/ipc.gypi +++ b/chromium/ipc/ipc.gypi @@ -30,6 +30,7 @@ 'brokerable_attachment.h', 'brokerable_attachment_mac.cc', 'brokerable_attachment_win.cc', + 'export_template.h', 'handle_attachment_win.cc', 'handle_attachment_win.h', 'handle_win.cc', @@ -69,6 +70,8 @@ 'ipc_message_generator.h', 'ipc_message_macros.h', 'ipc_message_start.h', + 'ipc_message_templates.h', + 'ipc_message_templates_impl.h', 'ipc_message_utils.cc', 'ipc_message_utils.h', 'ipc_param_traits.h', @@ -93,6 +96,8 @@ 'message_filter.h', 'message_filter_router.cc', 'message_filter_router.h', + 'message_router.cc', + 'message_router.h', 'param_traits_log_macros.h', 'param_traits_macros.h', 'param_traits_read_macros.h', diff --git a/chromium/ipc/ipc_channel.h b/chromium/ipc/ipc_channel.h index dd882bb5cc0..a008e7e15d5 100644 --- a/chromium/ipc/ipc_channel.h +++ b/chromium/ipc/ipc_channel.h @@ -12,6 +12,7 @@ #include "base/compiler_specific.h" #include "base/files/scoped_file.h" +#include "base/memory/scoped_ptr.h" #include "base/process/process.h" #include "build/build_config.h" #include "ipc/ipc_channel_handle.h" @@ -164,6 +165,9 @@ class IPC_EXPORT Channel : public Endpoint { // connect to a pre-existing pipe. Note, calling Connect() // will not block the calling thread and may complete // asynchronously. + // + // The subclass implementation must call WillConnect() at the beginning of its + // implementation. virtual bool Connect() WARN_UNUSED_RESULT = 0; // Close this Channel explicitly. May be called multiple times. @@ -223,6 +227,7 @@ class IPC_EXPORT Channel : public Endpoint { // message from client to server we need to send the PID from the global // PID namespace. static void SetGlobalPid(int pid); + static int GetGlobalPid(); #endif #if defined(OS_ANDROID) @@ -253,6 +258,16 @@ class IPC_EXPORT Channel : public Endpoint { void* buffer_; size_t length_; }; + + // Endpoint overrides. + void OnSetAttachmentBrokerEndpoint() override; + + // Subclasses must call this method at the beginning of their implementation + // of Connect(). + void WillConnect(); + + private: + bool did_start_connect_ = false; }; #if defined(OS_POSIX) diff --git a/chromium/ipc/ipc_channel_common.cc b/chromium/ipc/ipc_channel_common.cc index c12a360b64c..69abc3412b7 100644 --- a/chromium/ipc/ipc_channel_common.cc +++ b/chromium/ipc/ipc_channel_common.cc @@ -52,5 +52,13 @@ bool Channel::IsSendThreadSafe() const { return false; } +void Channel::OnSetAttachmentBrokerEndpoint() { + CHECK(!did_start_connect_); +} + +void Channel::WillConnect() { + did_start_connect_ = true; +} + } // namespace IPC diff --git a/chromium/ipc/ipc_channel_nacl.cc b/chromium/ipc/ipc_channel_nacl.cc index 84d77f68d07..3515202182c 100644 --- a/chromium/ipc/ipc_channel_nacl.cc +++ b/chromium/ipc/ipc_channel_nacl.cc @@ -155,6 +155,8 @@ base::ProcessId ChannelNacl::GetSelfPID() const { } bool ChannelNacl::Connect() { + WillConnect(); + if (pipe_ == -1) { DLOG(WARNING) << "Channel creation failed: " << pipe_name_; return false; diff --git a/chromium/ipc/ipc_channel_posix.cc b/chromium/ipc/ipc_channel_posix.cc index f53a8fe36ec..4b6d7facb7a 100644 --- a/chromium/ipc/ipc_channel_posix.cc +++ b/chromium/ipc/ipc_channel_posix.cc @@ -338,6 +338,8 @@ bool ChannelPosix::CreatePipe( } bool ChannelPosix::Connect() { + WillConnect(); + if (!server_listen_pipe_.is_valid() && !pipe_.is_valid()) { DLOG(WARNING) << "Channel creation failed: " << pipe_name_; return false; @@ -613,6 +615,10 @@ bool ChannelPosix::IsNamedServerInitialized( void ChannelPosix::SetGlobalPid(int pid) { global_pid_ = pid; } +// static +int ChannelPosix::GetGlobalPid() { + return global_pid_; +} #endif // OS_LINUX // Called by libevent when we can read from the pipe without blocking. @@ -1125,6 +1131,9 @@ bool Channel::IsNamedServerInitialized( void Channel::SetGlobalPid(int pid) { ChannelPosix::SetGlobalPid(pid); } +int Channel::GetGlobalPid() { + return ChannelPosix::GetGlobalPid(); +} #endif // OS_LINUX } // namespace IPC diff --git a/chromium/ipc/ipc_channel_posix.h b/chromium/ipc/ipc_channel_posix.h index ddeb60ea365..14bb95c48e2 100644 --- a/chromium/ipc/ipc_channel_posix.h +++ b/chromium/ipc/ipc_channel_posix.h @@ -65,6 +65,7 @@ class IPC_EXPORT ChannelPosix : public Channel, static bool IsNamedServerInitialized(const std::string& channel_id); #if defined(OS_LINUX) static void SetGlobalPid(int pid); + static int GetGlobalPid(); #endif // OS_LINUX private: diff --git a/chromium/ipc/ipc_channel_posix_unittest.cc b/chromium/ipc/ipc_channel_posix_unittest.cc index c122b719508..29f0d392d69 100644 --- a/chromium/ipc/ipc_channel_posix_unittest.cc +++ b/chromium/ipc/ipc_channel_posix_unittest.cc @@ -148,39 +148,11 @@ void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle, IPC::Channel::Mode mode) { const std::string& name = handle->name; - int socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); - ASSERT_GE(socket_fd, 0) << name; - ASSERT_GE(fcntl(socket_fd, F_SETFL, O_NONBLOCK), 0); - struct sockaddr_un server_address = { 0 }; - memset(&server_address, 0, sizeof(server_address)); - server_address.sun_family = AF_UNIX; - int path_len = snprintf(server_address.sun_path, IPC::kMaxSocketNameLength, - "%s", name.c_str()); - DCHECK_EQ(static_cast<int>(name.length()), path_len); - size_t server_address_len = offsetof(struct sockaddr_un, - sun_path) + path_len + 1; - + int socket_fd = 0; if (mode == IPC::Channel::MODE_NAMED_SERVER) { - // Only one server at a time. Cleanup garbage if it exists. - unlink(name.c_str()); - // Make sure the path we need exists. - base::FilePath path(name); - base::FilePath dir_path = path.DirName(); - ASSERT_TRUE(base::CreateDirectory(dir_path)); - ASSERT_GE(bind(socket_fd, - reinterpret_cast<struct sockaddr *>(&server_address), - server_address_len), 0) << server_address.sun_path - << ": " << strerror(errno) - << "(" << errno << ")"; - ASSERT_GE(listen(socket_fd, SOMAXCONN), 0) << server_address.sun_path - << ": " << strerror(errno) - << "(" << errno << ")"; + IPC::CreateServerUnixDomainSocket(base::FilePath(name), &socket_fd); } else if (mode == IPC::Channel::MODE_NAMED_CLIENT) { - ASSERT_GE(connect(socket_fd, - reinterpret_cast<struct sockaddr *>(&server_address), - server_address_len), 0) << server_address.sun_path - << ": " << strerror(errno) - << "(" << errno << ")"; + IPC::CreateClientUnixDomainSocket(base::FilePath(name), &socket_fd); } else { FAIL() << "Unknown mode " << mode; } diff --git a/chromium/ipc/ipc_channel_proxy.cc b/chromium/ipc/ipc_channel_proxy.cc index 5e702617e0d..2ebc9040a1e 100644 --- a/chromium/ipc/ipc_channel_proxy.cc +++ b/chromium/ipc/ipc_channel_proxy.cc @@ -263,24 +263,13 @@ void ChannelProxy::Context::AddFilter(MessageFilter* filter) { // Called on the listener's thread void ChannelProxy::Context::OnDispatchMessage(const Message& message) { -#if defined(IPC_MESSAGE_LOG_ENABLED) - Logging* logger = Logging::GetInstance(); - std::string name; - logger->GetMessageText(message.type(), &name, &message, NULL); - TRACE_EVENT1("ipc", "ChannelProxy::Context::OnDispatchMessage", - "name", name); -#else - TRACE_EVENT2("ipc", "ChannelProxy::Context::OnDispatchMessage", - "class", IPC_MESSAGE_ID_CLASS(message.type()), - "line", IPC_MESSAGE_ID_LINE(message.type())); -#endif - if (!listener_) return; OnDispatchConnected(); #ifdef IPC_MESSAGE_LOG_ENABLED + Logging* logger = Logging::GetInstance(); if (message.type() == IPC_LOGGING_ID) { logger->OnReceivedLoggingMessage(message); return; @@ -483,7 +472,7 @@ void ChannelProxy::RemoveFilter(MessageFilter* filter) { context_->ipc_task_runner()->PostTask( FROM_HERE, base::Bind(&Context::OnRemoveFilter, context_.get(), - make_scoped_refptr(filter))); + base::RetainedRef(filter))); } void ChannelProxy::ClearIPCTaskRunner() { @@ -497,6 +486,7 @@ base::ProcessId ChannelProxy::GetPeerPID() const { } void ChannelProxy::OnSetAttachmentBrokerEndpoint() { + CHECK(!did_init_); context()->set_attachment_broker_endpoint(is_attachment_broker_endpoint()); } diff --git a/chromium/ipc/ipc_channel_proxy.h b/chromium/ipc/ipc_channel_proxy.h index 9fdffb1ca57..495c5eb8a52 100644 --- a/chromium/ipc/ipc_channel_proxy.h +++ b/chromium/ipc/ipc_channel_proxy.h @@ -97,6 +97,11 @@ class IPC_EXPORT ChannelProxy : public Endpoint, public base::NonThreadSafe { Listener* listener, const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner); + // Constructs a ChannelProxy without initializing it. + ChannelProxy( + Listener* listener, + const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner); + ~ChannelProxy() override; // Initializes the channel proxy. Only call this once to initialize a channel @@ -159,9 +164,6 @@ class IPC_EXPORT ChannelProxy : public Endpoint, public base::NonThreadSafe { // to the internal state. ChannelProxy(Context* context); - ChannelProxy( - Listener* listener, - const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner); // Used internally to hold state that is referenced on the IPC thread. class Context : public base::RefCountedThreadSafe<Context>, diff --git a/chromium/ipc/ipc_channel_proxy_unittest_messages.h b/chromium/ipc/ipc_channel_proxy_unittest_messages.h index 20405eda0ef..288ce5353d3 100644 --- a/chromium/ipc/ipc_channel_proxy_unittest_messages.h +++ b/chromium/ipc/ipc_channel_proxy_unittest_messages.h @@ -17,8 +17,10 @@ namespace IPC { template <> struct ParamTraits<BadType> { - static void Write(Message* m, const BadType& p) {} - static bool Read(const Message* m, base::PickleIterator* iter, BadType* r) { + static void Write(base::Pickle* m, const BadType& p) {} + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + BadType* r) { return false; } static void Log(const BadType& p, std::string* l) {} diff --git a/chromium/ipc/ipc_channel_reader.cc b/chromium/ipc/ipc_channel_reader.cc index 9c6af49f2f1..e11fb93aea4 100644 --- a/chromium/ipc/ipc_channel_reader.cc +++ b/chromium/ipc/ipc_channel_reader.cc @@ -18,6 +18,30 @@ namespace IPC { namespace internal { +#ifdef IPC_MESSAGE_LOG_ENABLED + +namespace { +std::string GetMessageText(const Message& message) { + std::string name; + Logging::GetInstance()->GetMessageText( + message.type(), &name, &message, nullptr); + return name; +} +} // namespace + +#define EMIT_TRACE_EVENT(message) \ + TRACE_EVENT_WITH_FLOW1( \ + "ipc,toplevel", "ChannelReader::DispatchInputData", \ + (message).flags(), TRACE_EVENT_FLAG_FLOW_IN, "name", \ + GetMessageText(message)); +#else +#define EMIT_TRACE_EVENT(message) \ + TRACE_EVENT_WITH_FLOW2("ipc,toplevel", "ChannelReader::DispatchInputData", \ + (message).flags(), TRACE_EVENT_FLAG_FLOW_IN, "class", \ + IPC_MESSAGE_ID_CLASS((message).type()), "line", \ + IPC_MESSAGE_ID_LINE((message).type())); +#endif // IPC_MESSAGE_LOG_ENABLED + ChannelReader::ChannelReader(Listener* listener) : listener_(listener), max_input_buffer_size_(Channel::kMaximumReadBufferSize) { @@ -74,7 +98,7 @@ void ChannelReader::CleanUp() { } void ChannelReader::DispatchMessage(Message* m) { - EmitLogBeforeDispatch(*m); + EMIT_TRACE_EVENT(*m); listener_->OnMessageReceived(*m); HandleDispatchError(*m); } @@ -167,7 +191,7 @@ bool ChannelReader::HandleTranslatedMessage( const AttachmentIdVector& attachment_ids) { // Immediately handle internal messages. if (IsInternalMessage(*translated_message)) { - EmitLogBeforeDispatch(*translated_message); + EMIT_TRACE_EVENT(*translated_message); HandleInternalMessage(*translated_message); HandleDispatchError(*translated_message); return true; @@ -180,7 +204,7 @@ bool ChannelReader::HandleTranslatedMessage( // Ideally, the log would have been emitted prior to dispatching the // message, but that would require this class to know more about the // internals of attachment brokering, which should be avoided. - EmitLogBeforeDispatch(*translated_message); + EMIT_TRACE_EVENT(*translated_message); HandleDispatchError(*translated_message); return true; } @@ -223,21 +247,6 @@ void ChannelReader::HandleDispatchError(const Message& message) { listener_->OnBadMessageReceived(message); } -void ChannelReader::EmitLogBeforeDispatch(const Message& message) { -#ifdef IPC_MESSAGE_LOG_ENABLED - std::string name; - Logging::GetInstance()->GetMessageText(message.type(), &name, &message, NULL); - TRACE_EVENT_WITH_FLOW1("ipc,toplevel", "ChannelReader::DispatchInputData", - message.flags(), TRACE_EVENT_FLAG_FLOW_IN, "name", - name); -#else - TRACE_EVENT_WITH_FLOW2("ipc,toplevel", "ChannelReader::DispatchInputData", - message.flags(), TRACE_EVENT_FLAG_FLOW_IN, "class", - IPC_MESSAGE_ID_CLASS(message.type()), "line", - IPC_MESSAGE_ID_LINE(message.type())); -#endif -} - bool ChannelReader::DispatchAttachmentBrokerMessage(const Message& message) { #if USE_ATTACHMENT_BROKER if (IsAttachmentBrokerEndpoint() && GetAttachmentBroker()) { diff --git a/chromium/ipc/ipc_channel_reader.h b/chromium/ipc/ipc_channel_reader.h index ca2bd9476e5..2ee50af5362 100644 --- a/chromium/ipc/ipc_channel_reader.h +++ b/chromium/ipc/ipc_channel_reader.h @@ -158,9 +158,6 @@ class IPC_EXPORT ChannelReader : public SupportsAttachmentBrokering, // If there was a dispatch error, informs |listener_|. void HandleDispatchError(const Message& message); - // Emits logging associated with a Message that is about to be dispatched. - void EmitLogBeforeDispatch(const Message& message); - // Attachment broker messages should be dispatched out of band, since there // are no ordering restrictions on them, and they may be required to dispatch // the messages waiting in |queued_messages_|. diff --git a/chromium/ipc/ipc_channel_unittest.cc b/chromium/ipc/ipc_channel_unittest.cc index 0a49ca9abe0..134bec26edc 100644 --- a/chromium/ipc/ipc_channel_unittest.cc +++ b/chromium/ipc/ipc_channel_unittest.cc @@ -24,12 +24,7 @@ namespace { class IPCChannelTest : public IPCTestBase { }; -#if defined(OS_ANDROID) -#define MAYBE_ChannelTest DISABLED_ChannelTest -#else -#define MAYBE_ChannelTest ChannelTest -#endif -TEST_F(IPCChannelTest, MAYBE_ChannelTest) { +TEST_F(IPCChannelTest, ChannelTest) { Init("GenericClient"); // Set up IPC channel and start client. @@ -91,12 +86,7 @@ TEST_F(IPCChannelTest, ChannelTestExistingPipe) { } #endif // defined (OS_WIN) -#if defined(OS_ANDROID) -#define MAYBE_ChannelProxyTest DISABLED_ChannelProxyTest -#else -#define MAYBE_ChannelProxyTest ChannelProxyTest -#endif -TEST_F(IPCChannelTest, MAYBE_ChannelProxyTest) { +TEST_F(IPCChannelTest, ChannelProxyTest) { Init("GenericClient"); base::Thread thread("ChannelProxyTestServer"); @@ -133,7 +123,7 @@ class ChannelListenerWithOnConnectedSend : public IPC::TestChannelListener { } }; -#if defined(OS_WIN) || defined(OS_ANDROID) +#if defined(OS_WIN) // Acting flakey in Windows. http://crbug.com/129595 #define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected #else diff --git a/chromium/ipc/ipc_channel_win.cc b/chromium/ipc/ipc_channel_win.cc index 62918627c17..057b9a50787 100644 --- a/chromium/ipc/ipc_channel_win.cc +++ b/chromium/ipc/ipc_channel_win.cc @@ -392,6 +392,8 @@ bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle, } bool ChannelWin::Connect() { + WillConnect(); + DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once"; if (!thread_check_.get()) diff --git a/chromium/ipc/ipc_endpoint.h b/chromium/ipc/ipc_endpoint.h index 2ace1fe999c..3315f54e8a6 100644 --- a/chromium/ipc/ipc_endpoint.h +++ b/chromium/ipc/ipc_endpoint.h @@ -32,7 +32,7 @@ class IPC_EXPORT Endpoint : public Sender { // A callback that indicates that is_attachment_broker_endpoint() has been // changed. - virtual void OnSetAttachmentBrokerEndpoint(){}; + virtual void OnSetAttachmentBrokerEndpoint() = 0; // Whether this channel is used as an endpoint for sending and receiving // brokerable attachment messages to/from the broker process. diff --git a/chromium/ipc/ipc_message.cc b/chromium/ipc/ipc_message.cc index 71f72997452..289f08dab06 100644 --- a/chromium/ipc/ipc_message.cc +++ b/chromium/ipc/ipc_message.cc @@ -240,11 +240,13 @@ bool Message::AddPlaceholderBrokerableAttachmentWithId( return attachment_set()->AddAttachment(attachment); } -bool Message::WriteAttachment(scoped_refptr<MessageAttachment> attachment) { +bool Message::WriteAttachment( + scoped_refptr<base::Pickle::Attachment> attachment) { bool brokerable; size_t index; - bool success = - attachment_set()->AddAttachment(attachment, &index, &brokerable); + bool success = attachment_set()->AddAttachment( + make_scoped_refptr(static_cast<MessageAttachment*>(attachment.get())), + &index, &brokerable); DCHECK(success); // Write the type of descriptor. @@ -264,7 +266,7 @@ bool Message::WriteAttachment(scoped_refptr<MessageAttachment> attachment) { bool Message::ReadAttachment( base::PickleIterator* iter, - scoped_refptr<MessageAttachment>* attachment) const { + scoped_refptr<base::Pickle::Attachment>* attachment) const { bool brokerable; if (!iter->ReadBool(&brokerable)) return false; diff --git a/chromium/ipc/ipc_message.h b/chromium/ipc/ipc_message.h index a6c641d7104..56c3a46b5e9 100644 --- a/chromium/ipc/ipc_message.h +++ b/chromium/ipc/ipc_message.h @@ -221,13 +221,15 @@ class IPC_EXPORT Message : public base::Pickle { // WriteAttachment appends |attachment| to the end of the set. It returns // false iff the set is full. - bool WriteAttachment(scoped_refptr<MessageAttachment> attachment); + bool WriteAttachment( + scoped_refptr<base::Pickle::Attachment> attachment) override; // ReadAttachment parses an attachment given the parsing state |iter| and // writes it to |*attachment|. It returns true on success. - bool ReadAttachment(base::PickleIterator* iter, - scoped_refptr<MessageAttachment>* attachment) const; + bool ReadAttachment( + base::PickleIterator* iter, + scoped_refptr<base::Pickle::Attachment>* attachment) const override; // Returns true if there are any attachment in this message. - bool HasAttachments() const; + bool HasAttachments() const override; // Returns true if there are any MojoHandleAttachments in this message. bool HasMojoHandles() const; // Whether the message has any brokerable attachments. diff --git a/chromium/ipc/ipc_message_attachment.h b/chromium/ipc/ipc_message_attachment.h index dda06300012..7f7137d87b2 100644 --- a/chromium/ipc/ipc_message_attachment.h +++ b/chromium/ipc/ipc_message_attachment.h @@ -8,6 +8,7 @@ #include "base/files/file.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/pickle.h" #include "build/build_config.h" #include "ipc/ipc_export.h" @@ -15,8 +16,7 @@ namespace IPC { // Auxiliary data sent with |Message|. This can be a platform file descriptor // or a mojo |MessagePipe|. |GetType()| returns the type of the subclass. -class IPC_EXPORT MessageAttachment - : public base::RefCountedThreadSafe<MessageAttachment> { +class IPC_EXPORT MessageAttachment : public base::Pickle::Attachment { public: enum Type { TYPE_PLATFORM_FILE, // The instance is |PlatformFileAttachment|. @@ -33,7 +33,7 @@ class IPC_EXPORT MessageAttachment protected: friend class base::RefCountedThreadSafe<MessageAttachment>; MessageAttachment(); - virtual ~MessageAttachment(); + ~MessageAttachment() override; DISALLOW_COPY_AND_ASSIGN(MessageAttachment); }; diff --git a/chromium/ipc/ipc_message_macros.h b/chromium/ipc/ipc_message_macros.h index f9fc28e6c94..38f428e90aa 100644 --- a/chromium/ipc/ipc_message_macros.h +++ b/chromium/ipc/ipc_message_macros.h @@ -45,6 +45,11 @@ // // Generate destructors. // #include "ipc/struct_destructor_macros.h" // #include "path/to/YYY_message_generator.h" +// // Generate param traits size methods. +// #include "ipc/param_traits_size_macros.h" +// namespace IPC { +// #include "path/to/YYY_message_generator.h" +// } // namespace IPC // // Generate param traits write methods. // #include "ipc/param_traits_write_macros.h" // namespace IPC { @@ -196,14 +201,14 @@ #include <stdint.h> +#include <tuple> + #include "base/profiler/scoped_profile.h" +#include "ipc/export_template.h" +#include "ipc/ipc_message_templates.h" #include "ipc/ipc_message_utils.h" #include "ipc/param_traits_macros.h" -#if defined(IPC_MESSAGE_IMPL) -#include "ipc/ipc_message_utils_impl.h" -#endif - // Convenience macro for defining structs without inheritance. Should not need // to be subsequently redefined. #define IPC_STRUCT_BEGIN(struct_name) \ @@ -222,566 +227,63 @@ #define IPC_STRUCT_MEMBER(type, name, ...) type name; #define IPC_STRUCT_END() }; -// Message macros collect specific numbers of arguments and funnel them into -// the common message generation macro. These should never be redefined. -#define IPC_MESSAGE_CONTROL0(msg_class) \ - IPC_MESSAGE_DECL(EMPTY, CONTROL, msg_class, 0, 0, (), ()) - -#define IPC_MESSAGE_CONTROL1(msg_class, type1) \ - IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 1, 0, (type1), ()) - -#define IPC_MESSAGE_CONTROL2(msg_class, type1, type2) \ - IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 2, 0, (type1, type2), ()) - -#define IPC_MESSAGE_CONTROL3(msg_class, type1, type2, type3) \ - IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 3, 0, (type1, type2, type3), ()) - -#define IPC_MESSAGE_CONTROL4(msg_class, type1, type2, type3, type4) \ - IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 4, 0, (type1, type2, type3, type4), ()) - -#define IPC_MESSAGE_CONTROL5(msg_class, type1, type2, type3, type4, type5) \ - IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 5, 0, (type1, type2, type3, type4, type5), ()) - -#define IPC_MESSAGE_ROUTED0(msg_class) \ - IPC_MESSAGE_DECL(EMPTY, ROUTED, msg_class, 0, 0, (), ()) - -#define IPC_MESSAGE_ROUTED1(msg_class, type1) \ - IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 1, 0, (type1), ()) - -#define IPC_MESSAGE_ROUTED2(msg_class, type1, type2) \ - IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 2, 0, (type1, type2), ()) - -#define IPC_MESSAGE_ROUTED3(msg_class, type1, type2, type3) \ - IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 3, 0, (type1, type2, type3), ()) - -#define IPC_MESSAGE_ROUTED4(msg_class, type1, type2, type3, type4) \ - IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 4, 0, (type1, type2, type3, type4), ()) - -#define IPC_MESSAGE_ROUTED5(msg_class, type1, type2, type3, type4, type5) \ - IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 5, 0, (type1, type2, type3, type4, type5), ()) - -#define IPC_SYNC_MESSAGE_CONTROL0_0(msg_class) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 0, (), ()) - -#define IPC_SYNC_MESSAGE_CONTROL0_1(msg_class, type1_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 1, (), (type1_out)) - -#define IPC_SYNC_MESSAGE_CONTROL0_2(msg_class, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 2, (), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_CONTROL0_3(msg_class, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 3, (), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_CONTROL0_4(msg_class, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 4, (), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_CONTROL1_0(msg_class, type1_in) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 0, (type1_in), ()) - -#define IPC_SYNC_MESSAGE_CONTROL1_1(msg_class, type1_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 1, (type1_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_CONTROL1_2(msg_class, type1_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 2, (type1_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_CONTROL1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 3, (type1_in), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_CONTROL1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 4, (type1_in), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_CONTROL2_0(msg_class, type1_in, type2_in) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 0, (type1_in, type2_in), ()) - -#define IPC_SYNC_MESSAGE_CONTROL2_1(msg_class, type1_in, type2_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 1, (type1_in, type2_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_CONTROL2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 2, (type1_in, type2_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_CONTROL2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 3, (type1_in, type2_in), (type1_out, type2_out, type3_out)) +// Message macros collect arguments and funnel them into the common message +// generation macro. These should never be redefined. -#define IPC_SYNC_MESSAGE_CONTROL2_4(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 4, (type1_in, type2_in), (type1_out, type2_out, type3_out, type4_out)) +// Asynchronous messages have only in parameters and are declared like: +// IPC_MESSAGE_CONTROL(FooMsg, int, float) +#define IPC_MESSAGE_CONTROL(msg_class, ...) \ + IPC_MESSAGE_DECL(msg_class, CONTROL, IPC_TUPLE(__VA_ARGS__), void) +#define IPC_MESSAGE_ROUTED(msg_class, ...) \ + IPC_MESSAGE_DECL(msg_class, ROUTED, IPC_TUPLE(__VA_ARGS__), void) -#define IPC_SYNC_MESSAGE_CONTROL3_0(msg_class, type1_in, type2_in, type3_in) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 0, (type1_in, type2_in, type3_in), ()) - -#define IPC_SYNC_MESSAGE_CONTROL3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 1, (type1_in, type2_in, type3_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_CONTROL3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 2, (type1_in, type2_in, type3_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_CONTROL3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 3, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_CONTROL3_4(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 4, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_CONTROL4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 0, (type1_in, type2_in, type3_in, type4_in), ()) - -#define IPC_SYNC_MESSAGE_CONTROL4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 1, (type1_in, type2_in, type3_in, type4_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_CONTROL4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 2, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_CONTROL4_3(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 3, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_CONTROL4_4(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 4, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_CONTROL5_0(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 0, (type1_in, type2_in, type3_in, type4_in, type5_in), ()) - -#define IPC_SYNC_MESSAGE_CONTROL5_1(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 1, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_CONTROL5_2(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 2, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_CONTROL5_3(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 3, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_ROUTED0_0(msg_class) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 0, (), ()) - -#define IPC_SYNC_MESSAGE_ROUTED0_1(msg_class, type1_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 1, (), (type1_out)) - -#define IPC_SYNC_MESSAGE_ROUTED0_2(msg_class, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 2, (), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_ROUTED0_3(msg_class, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 3, (), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_ROUTED0_4(msg_class, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 4, (), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_ROUTED1_0(msg_class, type1_in) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 0, (type1_in), ()) - -#define IPC_SYNC_MESSAGE_ROUTED1_1(msg_class, type1_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 1, (type1_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_ROUTED1_2(msg_class, type1_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 2, (type1_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_ROUTED1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 3, (type1_in), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_ROUTED1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 4, (type1_in), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_ROUTED2_0(msg_class, type1_in, type2_in) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 0, (type1_in, type2_in), ()) - -#define IPC_SYNC_MESSAGE_ROUTED2_1(msg_class, type1_in, type2_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 1, (type1_in, type2_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_ROUTED2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 2, (type1_in, type2_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_ROUTED2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 3, (type1_in, type2_in), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_ROUTED2_4(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 4, (type1_in, type2_in), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_ROUTED3_0(msg_class, type1_in, type2_in, type3_in) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 0, (type1_in, type2_in, type3_in), ()) - -#define IPC_SYNC_MESSAGE_ROUTED3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 1, (type1_in, type2_in, type3_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_ROUTED3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 2, (type1_in, type2_in, type3_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_ROUTED3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 3, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_ROUTED3_4(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 4, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_ROUTED4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 0, (type1_in, type2_in, type3_in, type4_in), ()) - -#define IPC_SYNC_MESSAGE_ROUTED4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 1, (type1_in, type2_in, type3_in, type4_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_ROUTED4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 2, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_ROUTED4_3(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 3, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out)) - -#define IPC_SYNC_MESSAGE_ROUTED4_4(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 4, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out, type4_out)) - -#define IPC_SYNC_MESSAGE_ROUTED5_0(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 0, (type1_in, type2_in, type3_in, type4_in, type5_in), ()) - -#define IPC_SYNC_MESSAGE_ROUTED5_1(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 1, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out)) - -#define IPC_SYNC_MESSAGE_ROUTED5_2(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 2, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out)) - -#define IPC_SYNC_MESSAGE_ROUTED5_3(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 3, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out, type3_out)) - -// The following macros define the common set of methods provided by ASYNC -// message classes. -// This macro is for all the async IPCs that don't pass an extra parameter using -// IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. -#define IPC_ASYNC_MESSAGE_METHODS_GENERIC \ - template<class T, class S, class P, class Method> \ - static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \ - Method func) { \ - Schema::Param p; \ - if (Read(msg, &p)) { \ - base::DispatchToMethod(obj, func, p); \ - return true; \ - } \ - return false; \ - } - -// The following macros are for for async IPCs which have a dispatcher with an -// extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. -#define IPC_ASYNC_MESSAGE_METHODS_1 \ - IPC_ASYNC_MESSAGE_METHODS_GENERIC \ - template<class T, class S, class P, typename TA> \ - static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \ - void (T::*func)(P*, TA)) { \ - Schema::Param p; \ - if (Read(msg, &p)) { \ - (obj->*func)(parameter, base::get<0>(p)); \ - return true; \ - } \ - return false; \ - } -#define IPC_ASYNC_MESSAGE_METHODS_2 \ - IPC_ASYNC_MESSAGE_METHODS_GENERIC \ - template<class T, class S, class P, typename TA, typename TB> \ - static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \ - void (T::*func)(P*, TA, TB)) { \ - Schema::Param p; \ - if (Read(msg, &p)) { \ - (obj->*func)(parameter, base::get<0>(p), base::get<1>(p)); \ - return true; \ - } \ - return false; \ - } -#define IPC_ASYNC_MESSAGE_METHODS_3 \ - IPC_ASYNC_MESSAGE_METHODS_GENERIC \ - template<class T, class S, class P, typename TA, typename TB, typename TC> \ - static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \ - void (T::*func)(P*, TA, TB, TC)) { \ - Schema::Param p; \ - if (Read(msg, &p)) { \ - (obj->*func)(parameter, base::get<0>(p), base::get<1>(p), \ - base::get<2>(p)); \ - return true; \ - } \ - return false; \ - } -#define IPC_ASYNC_MESSAGE_METHODS_4 \ - IPC_ASYNC_MESSAGE_METHODS_GENERIC \ - template<class T, class S, class P, typename TA, typename TB, typename TC, \ - typename TD> \ - static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \ - void (T::*func)(P*, TA, TB, TC, TD)) { \ - Schema::Param p; \ - if (Read(msg, &p)) { \ - (obj->*func)(parameter, base::get<0>(p), base::get<1>(p), \ - base::get<2>(p), base::get<3>(p)); \ - return true; \ - } \ - return false; \ - } -#define IPC_ASYNC_MESSAGE_METHODS_5 \ - IPC_ASYNC_MESSAGE_METHODS_GENERIC \ - template<class T, class S, class P, typename TA, typename TB, typename TC, \ - typename TD, typename TE> \ - static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \ - void (T::*func)(P*, TA, TB, TC, TD, TE)) { \ - Schema::Param p; \ - if (Read(msg, &p)) { \ - (obj->*func)(parameter, base::get<0>(p), base::get<1>(p), \ - base::get<2>(p), base::get<3>(p), base::get<4>(p)); \ - return true; \ - } \ - return false; \ - } - -// The following macros define the common set of methods provided by SYNC -// message classes. -#define IPC_SYNC_MESSAGE_METHODS_GENERIC \ - template<class T, class S, class P, class Method> \ - static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \ - Method func) { \ - Schema::SendParam send_params; \ - bool ok = ReadSendParam(msg, &send_params); \ - return Schema::DispatchWithSendParams(ok, send_params, msg, obj, sender, \ - func); \ - } \ - template<class T, class P, class Method> \ - static bool DispatchDelayReply(const Message* msg, T* obj, P* parameter, \ - Method func) { \ - Schema::SendParam send_params; \ - bool ok = ReadSendParam(msg, &send_params); \ - return Schema::DispatchDelayReplyWithSendParams(ok, send_params, msg, \ - obj, func); \ - } -#define IPC_SYNC_MESSAGE_METHODS_0 \ - IPC_SYNC_MESSAGE_METHODS_GENERIC -#define IPC_SYNC_MESSAGE_METHODS_1 \ - IPC_SYNC_MESSAGE_METHODS_GENERIC \ - template<typename TA> \ - static void WriteReplyParams(Message* reply, TA a) { \ - Schema::WriteReplyParams(reply, a); \ - } -#define IPC_SYNC_MESSAGE_METHODS_2 \ - IPC_SYNC_MESSAGE_METHODS_GENERIC \ - template<typename TA, typename TB> \ - static void WriteReplyParams(Message* reply, TA a, TB b) { \ - Schema::WriteReplyParams(reply, a, b); \ - } -#define IPC_SYNC_MESSAGE_METHODS_3 \ - IPC_SYNC_MESSAGE_METHODS_GENERIC \ - template<typename TA, typename TB, typename TC> \ - static void WriteReplyParams(Message* reply, TA a, TB b, TC c) { \ - Schema::WriteReplyParams(reply, a, b, c); \ - } -#define IPC_SYNC_MESSAGE_METHODS_4 \ - IPC_SYNC_MESSAGE_METHODS_GENERIC \ - template<typename TA, typename TB, typename TC, typename TD> \ - static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) { \ - Schema::WriteReplyParams(reply, a, b, c, d); \ - } -#define IPC_SYNC_MESSAGE_METHODS_5 \ - IPC_SYNC_MESSAGE_METHODS_GENERIC \ - template<typename TA, typename TB, typename TC, typename TD, typename TE> \ - static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d, TE e) { \ - Schema::WriteReplyParams(reply, a, b, c, d, e); \ - } - -// Common message macro which dispatches into one of the 6 (sync x kind) -// routines. There is a way that these 6 cases can be lumped together, -// but the macros get very complicated in that case. -// Note: intended be redefined to generate other information. -#define IPC_MESSAGE_DECL(sync, kind, msg_class, \ - in_cnt, out_cnt, in_list, out_list) \ - IPC_##sync##_##kind##_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - IPC_MESSAGE_EXTRA(sync, kind, msg_class, in_cnt, out_cnt, in_list, out_list) - -#define IPC_EMPTY_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - class IPC_MESSAGE_EXPORT msg_class : public IPC::Message { \ - public: \ - typedef IPC::Message Schema; \ - enum { ID = IPC_MESSAGE_ID() }; \ - msg_class() : IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL) {} \ - static void Log(std::string* name, const Message* msg, std::string* l); \ - }; - -#define IPC_EMPTY_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - class IPC_MESSAGE_EXPORT msg_class : public IPC::Message { \ - public: \ - typedef IPC::Message Schema; \ - enum { ID = IPC_MESSAGE_ID() }; \ - msg_class(int32_t routing_id) \ - : IPC::Message(routing_id, ID, PRIORITY_NORMAL) {} \ - static void Log(std::string* name, const Message* msg, std::string* l); \ - }; - -#define IPC_ASYNC_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - class IPC_MESSAGE_EXPORT msg_class : public IPC::Message { \ - public: \ - typedef IPC::MessageSchema<IPC_TUPLE_IN_##in_cnt in_list> Schema; \ - typedef Schema::Param Param; \ - enum { ID = IPC_MESSAGE_ID() }; \ - msg_class(IPC_TYPE_IN_##in_cnt in_list); \ - ~msg_class() override; \ - static bool Read(const Message* msg, Schema::Param* p); \ - static void Log(std::string* name, const Message* msg, std::string* l); \ - IPC_ASYNC_MESSAGE_METHODS_##in_cnt \ - }; - -#define IPC_ASYNC_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - class IPC_MESSAGE_EXPORT msg_class : public IPC::Message { \ - public: \ - typedef IPC::MessageSchema<IPC_TUPLE_IN_##in_cnt in_list> Schema; \ - typedef Schema::Param Param; \ - enum { ID = IPC_MESSAGE_ID() }; \ - msg_class(int32_t routing_id IPC_COMMA_##in_cnt \ - IPC_TYPE_IN_##in_cnt in_list); \ - ~msg_class() override; \ - static bool Read(const Message* msg, Schema::Param* p); \ - static void Log(std::string* name, const Message* msg, std::string* l); \ - IPC_ASYNC_MESSAGE_METHODS_##in_cnt \ - }; - -#define IPC_SYNC_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - class IPC_MESSAGE_EXPORT msg_class : public IPC::SyncMessage { \ - public: \ - typedef IPC::SyncMessageSchema<IPC_TUPLE_IN_##in_cnt in_list, \ - IPC_TUPLE_OUT_##out_cnt out_list> Schema; \ - typedef Schema::ReplyParam ReplyParam; \ - typedef Schema::SendParam SendParam; \ - enum { ID = IPC_MESSAGE_ID() }; \ - msg_class(IPC_TYPE_IN_##in_cnt in_list \ - IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \ - IPC_TYPE_OUT_##out_cnt out_list); \ - ~msg_class() override; \ - static bool ReadSendParam(const Message* msg, Schema::SendParam* p); \ - static bool ReadReplyParam( \ - const Message* msg, \ - base::TupleTypes<ReplyParam>::ValueTuple* p); \ - static void Log(std::string* name, const Message* msg, std::string* l); \ - IPC_SYNC_MESSAGE_METHODS_##out_cnt \ - }; - -#define IPC_SYNC_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - class IPC_MESSAGE_EXPORT msg_class : public IPC::SyncMessage { \ - public: \ - typedef IPC::SyncMessageSchema<IPC_TUPLE_IN_##in_cnt in_list, \ - IPC_TUPLE_OUT_##out_cnt out_list> Schema; \ - typedef Schema::ReplyParam ReplyParam; \ - typedef Schema::SendParam SendParam; \ - enum { ID = IPC_MESSAGE_ID() }; \ - msg_class(int32_t routing_id \ - IPC_COMMA_OR_##in_cnt(IPC_COMMA_##out_cnt) \ - IPC_TYPE_IN_##in_cnt in_list \ - IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \ - IPC_TYPE_OUT_##out_cnt out_list); \ - ~msg_class() override; \ - static bool ReadSendParam(const Message* msg, Schema::SendParam* p); \ - static bool ReadReplyParam( \ - const Message* msg, \ - base::TupleTypes<ReplyParam>::ValueTuple* p); \ - static void Log(std::string* name, const Message* msg, std::string* l); \ - IPC_SYNC_MESSAGE_METHODS_##out_cnt \ - }; +// Synchronous messages have both in and out parameters, so the lists need to +// be parenthesized to disambiguate: +// IPC_SYNC_MESSAGE_CONTROL(BarMsg, (int, int), (bool)) +// +// Implementation detail: The parentheses supplied by the caller for +// disambiguation are also used to trigger the IPC_TUPLE invocations below, +// so "IPC_TUPLE in" and "IPC_TUPLE out" are intentional. +#define IPC_SYNC_MESSAGE_CONTROL(msg_class, in, out) \ + IPC_MESSAGE_DECL(msg_class, CONTROL, IPC_TUPLE in, IPC_TUPLE out) +#define IPC_SYNC_MESSAGE_ROUTED(msg_class, in, out) \ + IPC_MESSAGE_DECL(msg_class, ROUTED, IPC_TUPLE in, IPC_TUPLE out) + +#define IPC_TUPLE(...) IPC::CheckedTuple<__VA_ARGS__>::Tuple + +#define IPC_MESSAGE_DECL(msg_name, kind, in_tuple, out_tuple) \ + struct IPC_MESSAGE_EXPORT msg_name##_Meta { \ + using InTuple = in_tuple; \ + using OutTuple = out_tuple; \ + enum { ID = IPC_MESSAGE_ID() }; \ + static const IPC::MessageKind kKind = IPC::MessageKind::kind; \ + static const char kName[]; \ + }; \ + extern template class EXPORT_TEMPLATE_DECLARE(IPC_MESSAGE_EXPORT) \ + IPC::MessageT<msg_name##_Meta>; \ + using msg_name = IPC::MessageT<msg_name##_Meta>; \ + IPC_MESSAGE_EXTRA(msg_name) #if defined(IPC_MESSAGE_IMPL) -// "Implementation" inclusion produces constructors, destructors, and -// logging functions, except for the no-arg special cases, where the -// implementation occurs in the declaration, and there is no special -// logging function. -#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \ - in_cnt, out_cnt, in_list, out_list) \ - IPC_##sync##_##kind##_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - IPC_##sync##_MESSAGE_LOG(msg_class) - -#define IPC_EMPTY_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) -#define IPC_EMPTY_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) - -#define IPC_ASYNC_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - msg_class::msg_class(IPC_TYPE_IN_##in_cnt in_list) : \ - IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL) { \ - Schema::Write(this, IPC_NAME_IN_##in_cnt in_list); \ - } \ - msg_class::~msg_class() {} \ - bool msg_class::Read(const Message* msg, Schema::Param* p) { \ - return Schema::Read(msg, p); \ - } - -#define IPC_ASYNC_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - msg_class::msg_class(int32_t routing_id IPC_COMMA_##in_cnt \ - IPC_TYPE_IN_##in_cnt in_list) : \ - IPC::Message(routing_id, ID, PRIORITY_NORMAL) { \ - Schema::Write(this, IPC_NAME_IN_##in_cnt in_list); \ - } \ - msg_class::~msg_class() {} \ - bool msg_class::Read(const Message* msg, Schema::Param* p) { \ - return Schema::Read(msg, p); \ - } - -#define IPC_SYNC_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - msg_class::msg_class(IPC_TYPE_IN_##in_cnt in_list \ - IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \ - IPC_TYPE_OUT_##out_cnt out_list) : \ - IPC::SyncMessage(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL, \ - new IPC::ParamDeserializer<Schema::ReplyParam>( \ - IPC_NAME_OUT_##out_cnt out_list)) { \ - Schema::Write(this, IPC_NAME_IN_##in_cnt in_list); \ - } \ - msg_class::~msg_class() {} \ - bool msg_class::ReadSendParam(const Message* msg, Schema::SendParam* p) { \ - return Schema::ReadSendParam(msg, p); \ - } \ - bool msg_class::ReadReplyParam( \ - const Message* msg, \ - base::TupleTypes<ReplyParam>::ValueTuple* p) { \ - return Schema::ReadReplyParam(msg, p); \ - } - -#define IPC_SYNC_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \ - msg_class::msg_class(int32_t routing_id \ - IPC_COMMA_OR_##in_cnt(IPC_COMMA_##out_cnt) \ - IPC_TYPE_IN_##in_cnt in_list \ - IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \ - IPC_TYPE_OUT_##out_cnt out_list) : \ - IPC::SyncMessage(routing_id, ID, PRIORITY_NORMAL, \ - new IPC::ParamDeserializer<Schema::ReplyParam>( \ - IPC_NAME_OUT_##out_cnt out_list)) { \ - Schema::Write(this, IPC_NAME_IN_##in_cnt in_list); \ - } \ - msg_class::~msg_class() {} \ - bool msg_class::ReadSendParam(const Message* msg, Schema::SendParam* p) { \ - return Schema::ReadSendParam(msg, p); \ - } \ - bool msg_class::ReadReplyParam( \ - const Message* msg, \ - base::TupleTypes<ReplyParam>::ValueTuple* p) { \ - return Schema::ReadReplyParam(msg, p); \ - } - -#define IPC_EMPTY_MESSAGE_LOG(msg_class) \ - void msg_class::Log(std::string* name, \ - const Message* msg, \ - std::string* l) { \ - if (name) \ - *name = #msg_class; \ - } - -#define IPC_ASYNC_MESSAGE_LOG(msg_class) \ - void msg_class::Log(std::string* name, \ - const Message* msg, \ - std::string* l) { \ - if (name) \ - *name = #msg_class; \ - if (!msg || !l) \ - return; \ - Schema::Param p; \ - if (Schema::Read(msg, &p)) \ - IPC::LogParam(p, l); \ - } - -#define IPC_SYNC_MESSAGE_LOG(msg_class) \ - void msg_class::Log(std::string* name, \ - const Message* msg, \ - std::string* l) { \ - if (name) \ - *name = #msg_class; \ - if (!msg || !l) \ - return; \ - if (msg->is_sync()) { \ - base::TupleTypes<Schema::SendParam>::ValueTuple p; \ - if (Schema::ReadSendParam(msg, &p)) \ - IPC::LogParam(p, l); \ - AddOutputParamsToLog(msg, l); \ - } else { \ - base::TupleTypes<Schema::ReplyParam>::ValueTuple p; \ - if (Schema::ReadReplyParam(msg, &p)) \ - IPC::LogParam(p, l); \ - } \ - } +// "Implementation" inclusion provides the explicit template definition +// for msg_name. +#define IPC_MESSAGE_EXTRA(msg_name) \ + const char msg_name##_Meta::kName[] = #msg_name; \ + IPC_MESSAGE_DEFINE_KIND(msg_name) \ + template class EXPORT_TEMPLATE_DEFINE(IPC_MESSAGE_EXPORT) \ + IPC::MessageT<msg_name##_Meta>; + +// MSVC has an intentionally non-compliant "feature" that results in LNK2005 +// ("symbol already defined") errors if we provide an out-of-line definition +// for kKind. Microsoft's official response is to test for _MSC_EXTENSIONS: +// https://connect.microsoft.com/VisualStudio/feedback/details/786583/ +#if defined(_MSC_EXTENSIONS) +#define IPC_MESSAGE_DEFINE_KIND(msg_name) +#else +#define IPC_MESSAGE_DEFINE_KIND(msg_name) \ + const IPC::MessageKind msg_name##_Meta::kKind; +#endif #elif defined(IPC_MESSAGE_MACROS_LOG_ENABLED) @@ -790,95 +292,22 @@ #endif // "Log table" inclusion produces extra logging registration code. -#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \ - in_cnt, out_cnt, in_list, out_list) \ - class LoggerRegisterHelper##msg_class { \ - public: \ - LoggerRegisterHelper##msg_class() { \ - const uint32_t msg_id = static_cast<uint32_t>(msg_class::ID); \ - IPC_LOG_TABLE_ADD_ENTRY(msg_id, msg_class::Log); \ - } \ - }; \ - LoggerRegisterHelper##msg_class g_LoggerRegisterHelper##msg_class; +#define IPC_MESSAGE_EXTRA(msg_name) \ + class LoggerRegisterHelper##msg_name { \ + public: \ + LoggerRegisterHelper##msg_name() { \ + const uint32_t msg_id = static_cast<uint32_t>(msg_name::ID); \ + IPC_LOG_TABLE_ADD_ENTRY(msg_id, msg_name::Log); \ + } \ + }; \ + LoggerRegisterHelper##msg_name g_LoggerRegisterHelper##msg_name; #else // Normal inclusion produces nothing extra. -#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \ - in_cnt, out_cnt, in_list, out_list) - -#endif // defined(IPC_MESSAGE_IMPL) - -// Handle variable sized argument lists. These are usually invoked by token -// pasting against the argument counts. -#define IPC_TYPE_IN_0() -#define IPC_TYPE_IN_1(t1) const t1& arg1 -#define IPC_TYPE_IN_2(t1, t2) const t1& arg1, const t2& arg2 -#define IPC_TYPE_IN_3(t1, t2, t3) const t1& arg1, const t2& arg2, const t3& arg3 -#define IPC_TYPE_IN_4(t1, t2, t3, t4) const t1& arg1, const t2& arg2, const t3& arg3, const t4& arg4 -#define IPC_TYPE_IN_5(t1, t2, t3, t4, t5) const t1& arg1, const t2& arg2, const t3& arg3, const t4& arg4, const t5& arg5 - -#define IPC_TYPE_OUT_0() -#define IPC_TYPE_OUT_1(t1) t1* arg6 -#define IPC_TYPE_OUT_2(t1, t2) t1* arg6, t2* arg7 -#define IPC_TYPE_OUT_3(t1, t2, t3) t1* arg6, t2* arg7, t3* arg8 -#define IPC_TYPE_OUT_4(t1, t2, t3, t4) t1* arg6, t2* arg7, t3* arg8, \ - t4* arg9 - -#define IPC_TUPLE_IN_0() base::Tuple<> -#define IPC_TUPLE_IN_1(t1) base::Tuple<t1> -#define IPC_TUPLE_IN_2(t1, t2) base::Tuple<t1, t2> -#define IPC_TUPLE_IN_3(t1, t2, t3) base::Tuple<t1, t2, t3> -#define IPC_TUPLE_IN_4(t1, t2, t3, t4) base::Tuple<t1, t2, t3, t4> -#define IPC_TUPLE_IN_5(t1, t2, t3, t4, t5) base::Tuple<t1, t2, t3, t4, t5> - -#define IPC_TUPLE_OUT_0() base::Tuple<> -#define IPC_TUPLE_OUT_1(t1) base::Tuple<t1&> -#define IPC_TUPLE_OUT_2(t1, t2) base::Tuple<t1&, t2&> -#define IPC_TUPLE_OUT_3(t1, t2, t3) base::Tuple<t1&, t2&, t3&> -#define IPC_TUPLE_OUT_4(t1, t2, t3, t4) base::Tuple<t1&, t2&, t3&, t4&> - -#define IPC_NAME_IN_0() base::MakeTuple() -#define IPC_NAME_IN_1(t1) base::MakeRefTuple(arg1) -#define IPC_NAME_IN_2(t1, t2) base::MakeRefTuple(arg1, arg2) -#define IPC_NAME_IN_3(t1, t2, t3) base::MakeRefTuple(arg1, arg2, arg3) -#define IPC_NAME_IN_4(t1, t2, t3, t4) base::MakeRefTuple(arg1, arg2, \ - arg3, arg4) -#define IPC_NAME_IN_5(t1, t2, t3, t4, t5) base::MakeRefTuple(arg1, arg2, \ - arg3, arg4, arg5) - -#define IPC_NAME_OUT_0() base::MakeTuple() -#define IPC_NAME_OUT_1(t1) base::MakeRefTuple(*arg6) -#define IPC_NAME_OUT_2(t1, t2) base::MakeRefTuple(*arg6, *arg7) -#define IPC_NAME_OUT_3(t1, t2, t3) base::MakeRefTuple(*arg6, *arg7, \ - *arg8) -#define IPC_NAME_OUT_4(t1, t2, t3, t4) base::MakeRefTuple(*arg6, *arg7, \ - *arg8, *arg9) - -// There are places where the syntax requires a comma if there are input args, -// if there are input args and output args, or if there are input args or -// output args. These macros allow generation of the comma as needed; invoke -// by token pasting against the argument counts. -#define IPC_COMMA_0 -#define IPC_COMMA_1 , -#define IPC_COMMA_2 , -#define IPC_COMMA_3 , -#define IPC_COMMA_4 , -#define IPC_COMMA_5 , - -#define IPC_COMMA_AND_0(x) -#define IPC_COMMA_AND_1(x) x -#define IPC_COMMA_AND_2(x) x -#define IPC_COMMA_AND_3(x) x -#define IPC_COMMA_AND_4(x) x -#define IPC_COMMA_AND_5(x) x - -#define IPC_COMMA_OR_0(x) x -#define IPC_COMMA_OR_1(x) , -#define IPC_COMMA_OR_2(x) , -#define IPC_COMMA_OR_3(x) , -#define IPC_COMMA_OR_4(x) , -#define IPC_COMMA_OR_5(x) , +#define IPC_MESSAGE_EXTRA(msg_name) + +#endif // defined(IPC_MESSAGE_IMPL) // Message IDs // Note: we currently use __LINE__ to give unique IDs to messages within @@ -906,6 +335,7 @@ { \ typedef class_name _IpcMessageHandlerClass ALLOW_UNUSED_TYPE; \ void* param__ = NULL; \ + (void)param__; \ const IPC::Message& ipc_message__ = msg; \ switch (ipc_message__.type()) { @@ -973,8 +403,145 @@ } // This corresponds to an enum value from IPCMessageStart. -#define IPC_MESSAGE_CLASS(message) \ - IPC_MESSAGE_ID_CLASS(message.type()) +#define IPC_MESSAGE_CLASS(message) IPC_MESSAGE_ID_CLASS((message).type()) + +// Deprecated legacy macro names. +// TODO(mdempsky): Replace uses with generic names. + +#define IPC_MESSAGE_CONTROL0(msg) IPC_MESSAGE_CONTROL(msg) +#define IPC_MESSAGE_CONTROL1(msg, a) IPC_MESSAGE_CONTROL(msg, a) +#define IPC_MESSAGE_CONTROL2(msg, a, b) IPC_MESSAGE_CONTROL(msg, a, b) +#define IPC_MESSAGE_CONTROL3(msg, a, b, c) IPC_MESSAGE_CONTROL(msg, a, b, c) +#define IPC_MESSAGE_CONTROL4(msg, a, b, c, d) \ + IPC_MESSAGE_CONTROL(msg, a, b, c, d) +#define IPC_MESSAGE_CONTROL5(msg, a, b, c, d, e) \ + IPC_MESSAGE_CONTROL(msg, a, b, c, d, e) + +#define IPC_MESSAGE_ROUTED0(msg) IPC_MESSAGE_ROUTED(msg) +#define IPC_MESSAGE_ROUTED1(msg, a) IPC_MESSAGE_ROUTED(msg, a) +#define IPC_MESSAGE_ROUTED2(msg, a, b) IPC_MESSAGE_ROUTED(msg, a, b) +#define IPC_MESSAGE_ROUTED3(msg, a, b, c) IPC_MESSAGE_ROUTED(msg, a, b, c) +#define IPC_MESSAGE_ROUTED4(msg, a, b, c, d) IPC_MESSAGE_ROUTED(msg, a, b, c, d) +#define IPC_MESSAGE_ROUTED5(msg, a, b, c, d, e) \ + IPC_MESSAGE_ROUTED(msg, a, b, c, d, e) + +#define IPC_SYNC_MESSAGE_CONTROL0_0(msg) IPC_SYNC_MESSAGE_CONTROL(msg, (), ()) +#define IPC_SYNC_MESSAGE_CONTROL0_1(msg, a) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (), (a)) +#define IPC_SYNC_MESSAGE_CONTROL0_2(msg, a, b) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b)) +#define IPC_SYNC_MESSAGE_CONTROL0_3(msg, a, b, c) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b, c)) +#define IPC_SYNC_MESSAGE_CONTROL0_4(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (), (a, b, c, d)) +#define IPC_SYNC_MESSAGE_CONTROL1_0(msg, a) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a), ()) +#define IPC_SYNC_MESSAGE_CONTROL1_1(msg, a, b) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b)) +#define IPC_SYNC_MESSAGE_CONTROL1_2(msg, a, b, c) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c)) +#define IPC_SYNC_MESSAGE_CONTROL1_3(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c, d)) +#define IPC_SYNC_MESSAGE_CONTROL1_4(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a), (b, c, d, e)) +#define IPC_SYNC_MESSAGE_CONTROL2_0(msg, a, b) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), ()) +#define IPC_SYNC_MESSAGE_CONTROL2_1(msg, a, b, c) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c)) +#define IPC_SYNC_MESSAGE_CONTROL2_2(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d)) +#define IPC_SYNC_MESSAGE_CONTROL2_3(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d, e)) +#define IPC_SYNC_MESSAGE_CONTROL2_4(msg, a, b, c, d, e, f) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b), (c, d, e, f)) +#define IPC_SYNC_MESSAGE_CONTROL3_0(msg, a, b, c) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), ()) +#define IPC_SYNC_MESSAGE_CONTROL3_1(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d)) +#define IPC_SYNC_MESSAGE_CONTROL3_2(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e)) +#define IPC_SYNC_MESSAGE_CONTROL3_3(msg, a, b, c, d, e, f) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e, f)) +#define IPC_SYNC_MESSAGE_CONTROL3_4(msg, a, b, c, d, e, f, g) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c), (d, e, f, g)) +#define IPC_SYNC_MESSAGE_CONTROL4_0(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), ()) +#define IPC_SYNC_MESSAGE_CONTROL4_1(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e)) +#define IPC_SYNC_MESSAGE_CONTROL4_2(msg, a, b, c, d, e, f) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f)) +#define IPC_SYNC_MESSAGE_CONTROL4_3(msg, a, b, c, d, e, f, g) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f, g)) +#define IPC_SYNC_MESSAGE_CONTROL4_4(msg, a, b, c, d, e, f, g, h) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d), (e, f, g, h)) +#define IPC_SYNC_MESSAGE_CONTROL5_0(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), ()) +#define IPC_SYNC_MESSAGE_CONTROL5_1(msg, a, b, c, d, e, f) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f)) +#define IPC_SYNC_MESSAGE_CONTROL5_2(msg, a, b, c, d, e, f, g) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g)) +#define IPC_SYNC_MESSAGE_CONTROL5_3(msg, a, b, c, d, e, f, g, h) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g, h)) +#define IPC_SYNC_MESSAGE_CONTROL5_4(msg, a, b, c, d, e, f, g, h, i) \ + IPC_SYNC_MESSAGE_CONTROL(msg, (a, b, c, d, e), (f, g, h, i)) + +#define IPC_SYNC_MESSAGE_ROUTED0_0(msg) IPC_SYNC_MESSAGE_ROUTED(msg, (), ()) +#define IPC_SYNC_MESSAGE_ROUTED0_1(msg, a) IPC_SYNC_MESSAGE_ROUTED(msg, (), (a)) +#define IPC_SYNC_MESSAGE_ROUTED0_2(msg, a, b) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b)) +#define IPC_SYNC_MESSAGE_ROUTED0_3(msg, a, b, c) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b, c)) +#define IPC_SYNC_MESSAGE_ROUTED0_4(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (), (a, b, c, d)) +#define IPC_SYNC_MESSAGE_ROUTED1_0(msg, a) IPC_SYNC_MESSAGE_ROUTED(msg, (a), ()) +#define IPC_SYNC_MESSAGE_ROUTED1_1(msg, a, b) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b)) +#define IPC_SYNC_MESSAGE_ROUTED1_2(msg, a, b, c) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c)) +#define IPC_SYNC_MESSAGE_ROUTED1_3(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c, d)) +#define IPC_SYNC_MESSAGE_ROUTED1_4(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a), (b, c, d, e)) +#define IPC_SYNC_MESSAGE_ROUTED2_0(msg, a, b) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), ()) +#define IPC_SYNC_MESSAGE_ROUTED2_1(msg, a, b, c) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c)) +#define IPC_SYNC_MESSAGE_ROUTED2_2(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d)) +#define IPC_SYNC_MESSAGE_ROUTED2_3(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d, e)) +#define IPC_SYNC_MESSAGE_ROUTED2_4(msg, a, b, c, d, e, f) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b), (c, d, e, f)) +#define IPC_SYNC_MESSAGE_ROUTED3_0(msg, a, b, c) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), ()) +#define IPC_SYNC_MESSAGE_ROUTED3_1(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d)) +#define IPC_SYNC_MESSAGE_ROUTED3_2(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e)) +#define IPC_SYNC_MESSAGE_ROUTED3_3(msg, a, b, c, d, e, f) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e, f)) +#define IPC_SYNC_MESSAGE_ROUTED3_4(msg, a, b, c, d, e, f, g) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c), (d, e, f, g)) +#define IPC_SYNC_MESSAGE_ROUTED4_0(msg, a, b, c, d) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), ()) +#define IPC_SYNC_MESSAGE_ROUTED4_1(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e)) +#define IPC_SYNC_MESSAGE_ROUTED4_2(msg, a, b, c, d, e, f) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f)) +#define IPC_SYNC_MESSAGE_ROUTED4_3(msg, a, b, c, d, e, f, g) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f, g)) +#define IPC_SYNC_MESSAGE_ROUTED4_4(msg, a, b, c, d, e, f, g, h) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d), (e, f, g, h)) +#define IPC_SYNC_MESSAGE_ROUTED5_0(msg, a, b, c, d, e) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), ()) +#define IPC_SYNC_MESSAGE_ROUTED5_1(msg, a, b, c, d, e, f) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f)) +#define IPC_SYNC_MESSAGE_ROUTED5_2(msg, a, b, c, d, e, f, g) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g)) +#define IPC_SYNC_MESSAGE_ROUTED5_3(msg, a, b, c, d, e, f, g, h) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g, h)) +#define IPC_SYNC_MESSAGE_ROUTED5_4(msg, a, b, c, d, e, f, g, h, i) \ + IPC_SYNC_MESSAGE_ROUTED(msg, (a, b, c, d, e), (f, g, h, i)) #endif // IPC_IPC_MESSAGE_MACROS_H_ diff --git a/chromium/ipc/ipc_message_null_macros.h b/chromium/ipc/ipc_message_null_macros.h index 5a1ff4f4fa7..6eab78419be 100644 --- a/chromium/ipc/ipc_message_null_macros.h +++ b/chromium/ipc/ipc_message_null_macros.h @@ -24,6 +24,4 @@ #define IPC_STRUCT_TRAITS_PARENT(type) #define IPC_STRUCT_TRAITS_END() #define IPC_ENUM_TRAITS_VALIDATE(enum_name, validation_expression) -#define IPC_MESSAGE_DECL(sync, kind, msg_class, \ - in_cnt, out_cnt, in_list, out_list) - +#define IPC_MESSAGE_DECL(...) diff --git a/chromium/ipc/ipc_message_start.h b/chromium/ipc/ipc_message_start.h index 8197ac62970..c3abddc0ae2 100644 --- a/chromium/ipc/ipc_message_start.h +++ b/chromium/ipc/ipc_message_start.h @@ -11,17 +11,18 @@ enum IPCMessageStart { AutomationMsgStart = 0, FrameMsgStart, + PageMsgStart, ViewMsgStart, InputMsgStart, - PluginMsgStart, - PluginProcessMsgStart, ProfileImportMsgStart, TestMsgStart, DevToolsMsgStart, WorkerMsgStart, NaClMsgStart, UtilityMsgStart, + GpuChannelMsgStart, GpuMsgStart, + MediaMsgStart, ServiceMsgStart, PpapiMsgStart, FirefoxImporterUnittestMsgStart, @@ -75,7 +76,6 @@ enum IPCMessageStart { AppShimMsgStart, WebRtcLoggingMsgStart, TtsMsgStart, - MemoryBenchmarkMsgStart, WebSocketMsgStart, NaClHostMsgStart, WebRTCIdentityMsgStart, @@ -103,7 +103,6 @@ enum IPCMessageStart { PlatformNotificationMsgStart, CredentialManagerMsgStart, PDFMsgStart, - WebCacheMsgStart, ManifestManagerMsgStart, ExtensionUtilityMsgStart, GeofencingMsgStart, @@ -135,6 +134,8 @@ enum IPCMessageStart { StartupMetricMsgStart, ArcCameraMsgStart, DWriteFontProxyMsgStart, + MediaPlayerDelegateMsgStart, + SurfaceViewManagerMsgStart, LastIPCMsgStart // Must come last. }; diff --git a/chromium/ipc/ipc_message_templates.h b/chromium/ipc/ipc_message_templates.h new file mode 100644 index 00000000000..f5c28cca4a6 --- /dev/null +++ b/chromium/ipc/ipc_message_templates.h @@ -0,0 +1,215 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IPC_IPC_MESSAGE_TEMPLATES_H_ +#define IPC_IPC_MESSAGE_TEMPLATES_H_ + +#include <stdint.h> + +#include <tuple> +#include <type_traits> + +#include "base/logging.h" +#include "base/trace_event/trace_event.h" +#include "base/tuple.h" +#include "build/build_config.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_utils.h" + +namespace IPC { + +// This function is for all the async IPCs that don't pass an extra parameter +// using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. +template <typename ObjT, typename Method, typename P, typename Tuple> +void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) { + base::DispatchToMethod(obj, method, tuple); +} + +template <typename ObjT, + typename Method, + typename P, + typename Tuple, + size_t... Ns> +void DispatchToMethodImpl(ObjT* obj, + Method method, + P* parameter, + const Tuple& tuple, + base::IndexSequence<Ns...>) { + // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod? + (obj->*method)(parameter, std::get<Ns>(tuple)...); +} + +// The following function is for async IPCs which have a dispatcher with an +// extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. +template <typename ObjT, typename P, typename... Args, typename... Ts> +typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type +DispatchToMethod(ObjT* obj, + void (ObjT::*method)(P*, Args...), + P* parameter, + const std::tuple<Ts...>& tuple) { + DispatchToMethodImpl(obj, method, parameter, tuple, + base::MakeIndexSequence<sizeof...(Ts)>()); +} + +enum class MessageKind { + CONTROL, + ROUTED, +}; + +// Routing is a helper struct so MessageT's private common constructor has a +// different type signature than the public "int32_t routing_id" one. +struct Routing { + explicit Routing(int32_t id) : id(id) {} + int32_t id; +}; + +// We want to restrict MessageT's constructors so that a routing_id is always +// provided for ROUTED messages and never provided for CONTROL messages, so +// use the SFINAE technique from N4387's "Implementation Hint" section. +#if defined(COMPILER_MSVC) +// MSVC 2013 doesn't support default arguments for template member functions +// of templated classes, so there we have to rely on the DCHECKs instead. +// TODO(mdempsky): Reevaluate once MSVC 2015. +#define IPC_MESSAGET_SFINAE(x) +#else +#define IPC_MESSAGET_SFINAE(x) \ + template <bool X = (x), typename std::enable_if<X, bool>::type = false> +#endif + +// MessageT is the common template used for all user-defined message types. +// It's intended to be used via the macros defined in ipc_message_macros.h. +template <typename Meta, + typename InTuple = typename Meta::InTuple, + typename OutTuple = typename Meta::OutTuple> +class MessageT; + +// Asynchronous message partial specialization. +template <typename Meta, typename... Ins> +class MessageT<Meta, std::tuple<Ins...>, void> : public Message { + public: + using Param = std::tuple<Ins...>; + enum { ID = Meta::ID }; + + // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced + // with just MyMessage::Param. + using Schema = MessageT; + + IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) + MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) { + DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; + } + + IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) + MessageT(int32_t routing_id, const Ins&... ins) + : MessageT(Routing(routing_id), ins...) { + DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; + } + + static bool Read(const Message* msg, Param* p); + static void Log(std::string* name, const Message* msg, std::string* l); + + template <class T, class S, class P, class Method> + static bool Dispatch(const Message* msg, + T* obj, + S* sender, + P* parameter, + Method func) { + TRACE_EVENT0("ipc", Meta::kName); + Param p; + if (Read(msg, &p)) { + DispatchToMethod(obj, func, parameter, p); + return true; + } + return false; + } + + private: + MessageT(Routing routing, const Ins&... ins); +}; + +// Synchronous message partial specialization. +template <typename Meta, typename... Ins, typename... Outs> +class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>> + : public SyncMessage { + public: + using SendParam = std::tuple<Ins...>; + using ReplyParam = std::tuple<Outs...>; + enum { ID = Meta::ID }; + + // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can + // be replaced with just MyMessage::{Send,Reply}Param. + using Schema = MessageT; + + IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) + MessageT(const Ins&... ins, Outs*... outs) + : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) { + DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; + } + + IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) + MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs) + : MessageT(Routing(routing_id), ins..., outs...) { + DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; + } + + static bool ReadSendParam(const Message* msg, SendParam* p); + static bool ReadReplyParam(const Message* msg, ReplyParam* p); + static void WriteReplyParams(Message* reply, const Outs&... outs); + static void Log(std::string* name, const Message* msg, std::string* l); + + template <class T, class S, class P, class Method> + static bool Dispatch(const Message* msg, + T* obj, + S* sender, + P* parameter, + Method func) { + TRACE_EVENT0("ipc", Meta::kName); + SendParam send_params; + bool ok = ReadSendParam(msg, &send_params); + Message* reply = SyncMessage::GenerateReply(msg); + if (ok) { + ReplyParam reply_params; + base::DispatchToMethod(obj, func, send_params, &reply_params); + WriteParam(reply, reply_params); + LogReplyParamsToMessage(reply_params, msg); + } else { + NOTREACHED() << "Error deserializing message " << msg->type(); + reply->set_reply_error(); + } + sender->Send(reply); + return ok; + } + + template <class T, class P, class Method> + static bool DispatchDelayReply(const Message* msg, + T* obj, + P* parameter, + Method func) { + TRACE_EVENT0("ipc", Meta::kName); + SendParam send_params; + bool ok = ReadSendParam(msg, &send_params); + Message* reply = SyncMessage::GenerateReply(msg); + if (ok) { + std::tuple<Message&> t = std::tie(*reply); + ConnectMessageAndReply(msg, reply); + base::DispatchToMethod(obj, func, send_params, &t); + } else { + NOTREACHED() << "Error deserializing message " << msg->type(); + reply->set_reply_error(); + obj->Send(reply); + } + return ok; + } + + private: + MessageT(Routing routing, const Ins&... ins, Outs*... outs); +}; + +} // namespace IPC + +#if defined(IPC_MESSAGE_IMPL) +#include "ipc/ipc_message_templates_impl.h" +#endif + +#endif // IPC_IPC_MESSAGE_TEMPLATES_H_ diff --git a/chromium/ipc/ipc_message_templates_impl.h b/chromium/ipc/ipc_message_templates_impl.h new file mode 100644 index 00000000000..192d2efb93e --- /dev/null +++ b/chromium/ipc/ipc_message_templates_impl.h @@ -0,0 +1,112 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_ +#define IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_ + +#include <tuple> + +namespace IPC { + +template <typename... Ts> +class ParamDeserializer : public MessageReplyDeserializer { + public: + explicit ParamDeserializer(const std::tuple<Ts&...>& out) : out_(out) {} + + bool SerializeOutputParameters(const IPC::Message& msg, + base::PickleIterator iter) override { + return ReadParam(&msg, &iter, &out_); + } + + std::tuple<Ts&...> out_; +}; + +template <typename Meta, typename... Ins> +MessageT<Meta, std::tuple<Ins...>, void>::MessageT(Routing routing, + const Ins&... ins) + : Message(routing.id, ID, PRIORITY_NORMAL) { + WriteParam(this, std::tie(ins...)); +} + +template <typename Meta, typename... Ins> +bool MessageT<Meta, std::tuple<Ins...>, void>::Read(const Message* msg, + Param* p) { + base::PickleIterator iter(*msg); + return ReadParam(msg, &iter, p); +} + +template <typename Meta, typename... Ins> +void MessageT<Meta, std::tuple<Ins...>, void>::Log(std::string* name, + const Message* msg, + std::string* l) { + if (name) + *name = Meta::kName; + if (!msg || !l) + return; + Param p; + if (Read(msg, &p)) + LogParam(p, l); +} + +template <typename Meta, typename... Ins, typename... Outs> +MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>::MessageT( + Routing routing, + const Ins&... ins, + Outs*... outs) + : SyncMessage( + routing.id, + ID, + PRIORITY_NORMAL, + new ParamDeserializer<Outs...>(std::tie(*outs...))) { + WriteParam(this, std::tie(ins...)); +} + +template <typename Meta, typename... Ins, typename... Outs> +bool MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>::ReadSendParam( + const Message* msg, + SendParam* p) { + base::PickleIterator iter = SyncMessage::GetDataIterator(msg); + return ReadParam(msg, &iter, p); +} + +template <typename Meta, typename... Ins, typename... Outs> +bool MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>::ReadReplyParam( + const Message* msg, + ReplyParam* p) { + base::PickleIterator iter = SyncMessage::GetDataIterator(msg); + return ReadParam(msg, &iter, p); +} + +template <typename Meta, typename... Ins, typename... Outs> +void MessageT<Meta, + std::tuple<Ins...>, + std::tuple<Outs...>>::WriteReplyParams(Message* reply, + const Outs&... outs) { + WriteParam(reply, std::tie(outs...)); +} + +template <typename Meta, typename... Ins, typename... Outs> +void MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>::Log( + std::string* name, + const Message* msg, + std::string* l) { + if (name) + *name = Meta::kName; + if (!msg || !l) + return; + if (msg->is_sync()) { + SendParam p; + if (ReadSendParam(msg, &p)) + LogParam(p, l); + AddOutputParamsToLog(msg, l); + } else { + ReplyParam p; + if (ReadReplyParam(msg, &p)) + LogParam(p, l); + } +} + +} // namespace IPC + +#endif // IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_ diff --git a/chromium/ipc/ipc_message_utils.cc b/chromium/ipc/ipc_message_utils.cc index ea88b55a2a5..9edc3bbd4cd 100644 --- a/chromium/ipc/ipc_message_utils.cc +++ b/chromium/ipc/ipc_message_utils.cc @@ -67,12 +67,78 @@ void LogBytes(const std::vector<CharType>& data, std::string* out) { #endif } -bool ReadValue(const Message* m, +bool ReadValue(const base::Pickle* m, base::PickleIterator* iter, base::Value** value, int recursion); -void WriteValue(Message* m, const base::Value* value, int recursion) { +void GetValueSize(base::PickleSizer* sizer, + const base::Value* value, + int recursion) { + if (recursion > kMaxRecursionDepth) { + LOG(WARNING) << "Max recursion depth hit in GetValueSize."; + return; + } + + sizer->AddInt(); + switch (value->GetType()) { + case base::Value::TYPE_NULL: + break; + case base::Value::TYPE_BOOLEAN: + sizer->AddBool(); + break; + case base::Value::TYPE_INTEGER: + sizer->AddInt(); + break; + case base::Value::TYPE_DOUBLE: + sizer->AddDouble(); + break; + case base::Value::TYPE_STRING: { + const base::StringValue* result; + value->GetAsString(&result); + if (value->GetAsString(&result)) { + DCHECK(result); + GetParamSize(sizer, result->GetString()); + } else { + std::string str; + bool as_string_result = value->GetAsString(&str); + DCHECK(as_string_result); + GetParamSize(sizer, str); + } + break; + } + case base::Value::TYPE_BINARY: { + const base::BinaryValue* binary = + static_cast<const base::BinaryValue*>(value); + sizer->AddData(static_cast<int>(binary->GetSize())); + break; + } + case base::Value::TYPE_DICTIONARY: { + sizer->AddInt(); + const base::DictionaryValue* dict = + static_cast<const base::DictionaryValue*>(value); + for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); + it.Advance()) { + GetParamSize(sizer, it.key()); + GetValueSize(sizer, &it.value(), recursion + 1); + } + break; + } + case base::Value::TYPE_LIST: { + sizer->AddInt(); + const base::ListValue* list = static_cast<const base::ListValue*>(value); + for (base::ListValue::const_iterator it = list->begin(); + it != list->end(); ++it) { + GetValueSize(sizer, *it, recursion + 1); + } + break; + } + default: + NOTREACHED() << "Invalid base::Value type."; + } +} + +void WriteValue(base::Pickle* m, const base::Value* value, int recursion) { bool result; if (recursion > kMaxRecursionDepth) { LOG(WARNING) << "Max recursion depth hit in WriteValue."; @@ -145,7 +211,7 @@ void WriteValue(Message* m, const base::Value* value, int recursion) { // Helper for ReadValue that reads a DictionaryValue into a pre-allocated // object. -bool ReadDictionaryValue(const Message* m, +bool ReadDictionaryValue(const base::Pickle* m, base::PickleIterator* iter, base::DictionaryValue* value, int recursion) { @@ -167,7 +233,7 @@ bool ReadDictionaryValue(const Message* m, // Helper for ReadValue that reads a ReadListValue into a pre-allocated // object. -bool ReadListValue(const Message* m, +bool ReadListValue(const base::Pickle* m, base::PickleIterator* iter, base::ListValue* value, int recursion) { @@ -185,7 +251,7 @@ bool ReadListValue(const Message* m, return true; } -bool ReadValue(const Message* m, +bool ReadValue(const base::Pickle* m, base::PickleIterator* iter, base::Value** value, int recursion) { @@ -271,6 +337,8 @@ LogData::LogData() dispatch(0) { } +LogData::LogData(const LogData& other) = default; + LogData::~LogData() { } @@ -278,13 +346,18 @@ void ParamTraits<bool>::Log(const param_type& p, std::string* l) { l->append(p ? "true" : "false"); } -void ParamTraits<signed char>::Write(Message* m, const param_type& p) { +void ParamTraits<signed char>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddBytes(sizeof(param_type)); +} + +void ParamTraits<signed char>::Write(base::Pickle* m, const param_type& p) { m->WriteBytes(&p, sizeof(param_type)); } -bool ParamTraits<signed char>::Read(const Message* m, - base::PickleIterator* iter, - param_type* r) { +bool ParamTraits<signed char>::Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r) { const char* data; if (!iter->ReadBytes(&data, sizeof(param_type))) return false; @@ -296,11 +369,16 @@ void ParamTraits<signed char>::Log(const param_type& p, std::string* l) { l->append(base::IntToString(p)); } -void ParamTraits<unsigned char>::Write(Message* m, const param_type& p) { +void ParamTraits<unsigned char>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddBytes(sizeof(param_type)); +} + +void ParamTraits<unsigned char>::Write(base::Pickle* m, const param_type& p) { m->WriteBytes(&p, sizeof(param_type)); } -bool ParamTraits<unsigned char>::Read(const Message* m, +bool ParamTraits<unsigned char>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data; @@ -314,11 +392,16 @@ void ParamTraits<unsigned char>::Log(const param_type& p, std::string* l) { l->append(base::UintToString(p)); } -void ParamTraits<unsigned short>::Write(Message* m, const param_type& p) { +void ParamTraits<unsigned short>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddBytes(sizeof(param_type)); +} + +void ParamTraits<unsigned short>::Write(base::Pickle* m, const param_type& p) { m->WriteBytes(&p, sizeof(param_type)); } -bool ParamTraits<unsigned short>::Read(const Message* m, +bool ParamTraits<unsigned short>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data; @@ -340,6 +423,8 @@ void ParamTraits<unsigned int>::Log(const param_type& p, std::string* l) { l->append(base::UintToString(p)); } +#if defined(OS_WIN) || defined(OS_LINUX) || \ + (defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS)) void ParamTraits<long>::Log(const param_type& p, std::string* l) { l->append(base::Int64ToString(static_cast<int64_t>(p))); } @@ -347,6 +432,7 @@ void ParamTraits<long>::Log(const param_type& p, std::string* l) { void ParamTraits<unsigned long>::Log(const param_type& p, std::string* l) { l->append(base::Uint64ToString(static_cast<uint64_t>(p))); } +#endif void ParamTraits<long long>::Log(const param_type& p, std::string* l) { l->append(base::Int64ToString(static_cast<int64_t>(p))); @@ -360,11 +446,16 @@ void ParamTraits<float>::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("%e", p)); } -void ParamTraits<double>::Write(Message* m, const param_type& p) { +void ParamTraits<double>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddBytes(sizeof(param_type)); +} + +void ParamTraits<double>::Write(base::Pickle* m, const param_type& p) { m->WriteBytes(reinterpret_cast<const char*>(&p), sizeof(param_type)); } -bool ParamTraits<double>::Read(const Message* m, +bool ParamTraits<double>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; @@ -389,7 +480,13 @@ void ParamTraits<base::string16>::Log(const param_type& p, std::string* l) { l->append(base::UTF16ToUTF8(p)); } -void ParamTraits<std::vector<char> >::Write(Message* m, const param_type& p) { +void ParamTraits<std::vector<char>>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddData(static_cast<int>(p.size())); +} + +void ParamTraits<std::vector<char>>::Write(base::Pickle* m, + const param_type& p) { if (p.empty()) { m->WriteData(NULL, 0); } else { @@ -397,7 +494,7 @@ void ParamTraits<std::vector<char> >::Write(Message* m, const param_type& p) { } } -bool ParamTraits<std::vector<char>>::Read(const Message* m, +bool ParamTraits<std::vector<char>>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; @@ -414,8 +511,13 @@ void ParamTraits<std::vector<char> >::Log(const param_type& p, std::string* l) { LogBytes(p, l); } -void ParamTraits<std::vector<unsigned char> >::Write(Message* m, - const param_type& p) { +void ParamTraits<std::vector<unsigned char>>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddData(static_cast<int>(p.size())); +} + +void ParamTraits<std::vector<unsigned char>>::Write(base::Pickle* m, + const param_type& p) { if (p.empty()) { m->WriteData(NULL, 0); } else { @@ -424,7 +526,7 @@ void ParamTraits<std::vector<unsigned char> >::Write(Message* m, } } -bool ParamTraits<std::vector<unsigned char>>::Read(const Message* m, +bool ParamTraits<std::vector<unsigned char>>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; @@ -442,7 +544,15 @@ void ParamTraits<std::vector<unsigned char> >::Log(const param_type& p, LogBytes(p, l); } -void ParamTraits<std::vector<bool> >::Write(Message* m, const param_type& p) { +void ParamTraits<std::vector<bool>>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + GetParamSize(sizer, static_cast<int>(p.size())); + for (size_t i = 0; i < p.size(); ++i) + GetParamSize(sizer, static_cast<bool>(p[i])); +} + +void ParamTraits<std::vector<bool>>::Write(base::Pickle* m, + const param_type& p) { WriteParam(m, static_cast<int>(p.size())); // Cast to bool below is required because libc++'s // vector<bool>::const_reference is different from bool, and we want to avoid @@ -451,7 +561,7 @@ void ParamTraits<std::vector<bool> >::Write(Message* m, const param_type& p) { WriteParam(m, static_cast<bool>(p[i])); } -bool ParamTraits<std::vector<bool>>::Read(const Message* m, +bool ParamTraits<std::vector<bool>>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; @@ -477,13 +587,13 @@ void ParamTraits<std::vector<bool> >::Log(const param_type& p, std::string* l) { } void ParamTraits<BrokerableAttachment::AttachmentId>::Write( - Message* m, + base::Pickle* m, const param_type& p) { m->WriteBytes(p.nonce, BrokerableAttachment::kNonceSize); } bool ParamTraits<BrokerableAttachment::AttachmentId>::Read( - const Message* m, + const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char* data; @@ -498,12 +608,17 @@ void ParamTraits<BrokerableAttachment::AttachmentId>::Log(const param_type& p, l->append(base::HexEncode(p.nonce, BrokerableAttachment::kNonceSize)); } -void ParamTraits<base::DictionaryValue>::Write(Message* m, +void ParamTraits<base::DictionaryValue>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + GetValueSize(sizer, &p, 0); +} + +void ParamTraits<base::DictionaryValue>::Write(base::Pickle* m, const param_type& p) { WriteValue(m, &p, 0); } -bool ParamTraits<base::DictionaryValue>::Read(const Message* m, +bool ParamTraits<base::DictionaryValue>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int type; @@ -521,7 +636,8 @@ void ParamTraits<base::DictionaryValue>::Log(const param_type& p, } #if defined(OS_POSIX) -void ParamTraits<base::FileDescriptor>::Write(Message* m, const param_type& p) { +void ParamTraits<base::FileDescriptor>::Write(base::Pickle* m, + const param_type& p) { const bool valid = p.fd >= 0; WriteParam(m, valid); @@ -538,7 +654,7 @@ void ParamTraits<base::FileDescriptor>::Write(Message* m, const param_type& p) { } } -bool ParamTraits<base::FileDescriptor>::Read(const Message* m, +bool ParamTraits<base::FileDescriptor>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { *r = base::FileDescriptor(); @@ -551,11 +667,13 @@ bool ParamTraits<base::FileDescriptor>::Read(const Message* m, if (!valid) return true; - scoped_refptr<MessageAttachment> attachment; + scoped_refptr<base::Pickle::Attachment> attachment; if (!m->ReadAttachment(iter, &attachment)) return false; - *r = base::FileDescriptor(attachment->TakePlatformFile(), true); + *r = base::FileDescriptor( + static_cast<MessageAttachment*>(attachment.get())->TakePlatformFile(), + true); return true; } @@ -570,7 +688,7 @@ void ParamTraits<base::FileDescriptor>::Log(const param_type& p, #endif // defined(OS_POSIX) #if defined(OS_MACOSX) && !defined(OS_IOS) -void ParamTraits<base::SharedMemoryHandle>::Write(Message* m, +void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m, const param_type& p) { m->WriteInt(p.GetType()); @@ -584,7 +702,7 @@ void ParamTraits<base::SharedMemoryHandle>::Write(Message* m, size_t size = 0; bool result = p.GetSize(&size); DCHECK(result); - ParamTraits<size_t>::Write(m, size); + ParamTraits<uint32_t>::Write(m, static_cast<uint32_t>(size)); // If the caller intended to pass ownership to the IPC stack, release a // reference. @@ -595,7 +713,7 @@ void ParamTraits<base::SharedMemoryHandle>::Write(Message* m, } } -bool ParamTraits<base::SharedMemoryHandle>::Read(const Message* m, +bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { base::SharedMemoryHandle::TypeWireFormat type; @@ -632,11 +750,12 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const Message* m, if (!ParamTraits<MachPortMac>::Read(m, iter, &mach_port_mac)) return false; - size_t size; - if (!ParamTraits<size_t>::Read(m, iter, &size)) + uint32_t size; + if (!ParamTraits<uint32_t>::Read(m, iter, &size)) return false; - *r = base::SharedMemoryHandle(mach_port_mac.get_mach_port(), size, + *r = base::SharedMemoryHandle(mach_port_mac.get_mach_port(), + static_cast<size_t>(size), base::GetCurrentProcId()); return true; } @@ -658,19 +777,24 @@ void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p, } #elif defined(OS_WIN) -void ParamTraits<base::SharedMemoryHandle>::Write(Message* m, +void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m, const param_type& p) { m->WriteBool(p.NeedsBrokering()); if (p.NeedsBrokering()) { HandleWin handle_win(p.GetHandle(), HandleWin::DUPLICATE); ParamTraits<HandleWin>::Write(m, handle_win); + + // If the caller intended to pass ownership to the IPC stack, release a + // reference. + if (p.OwnershipPassesToIPC() && p.BelongsToCurrentProcess()) + p.Close(); } else { m->WriteInt(HandleToLong(p.GetHandle())); } } -bool ParamTraits<base::SharedMemoryHandle>::Read(const Message* m, +bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool needs_brokering; @@ -702,11 +826,16 @@ void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p, } #endif // defined(OS_MACOSX) && !defined(OS_IOS) -void ParamTraits<base::FilePath>::Write(Message* m, const param_type& p) { +void ParamTraits<base::FilePath>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + p.GetSizeForPickle(sizer); +} + +void ParamTraits<base::FilePath>::Write(base::Pickle* m, const param_type& p) { p.WriteToPickle(m); } -bool ParamTraits<base::FilePath>::Read(const Message* m, +bool ParamTraits<base::FilePath>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return r->ReadFromPickle(iter); @@ -716,11 +845,16 @@ void ParamTraits<base::FilePath>::Log(const param_type& p, std::string* l) { ParamTraits<base::FilePath::StringType>::Log(p.value(), l); } -void ParamTraits<base::ListValue>::Write(Message* m, const param_type& p) { +void ParamTraits<base::ListValue>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + GetValueSize(sizer, &p, 0); +} + +void ParamTraits<base::ListValue>::Write(base::Pickle* m, const param_type& p) { WriteValue(m, &p, 0); } -bool ParamTraits<base::ListValue>::Read(const Message* m, +bool ParamTraits<base::ListValue>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int type; @@ -736,13 +870,19 @@ void ParamTraits<base::ListValue>::Log(const param_type& p, std::string* l) { l->append(json); } -void ParamTraits<base::NullableString16>::Write(Message* m, +void ParamTraits<base::NullableString16>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + GetParamSize(sizer, p.string()); + GetParamSize(sizer, p.is_null()); +} + +void ParamTraits<base::NullableString16>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.string()); WriteParam(m, p.is_null()); } -bool ParamTraits<base::NullableString16>::Read(const Message* m, +bool ParamTraits<base::NullableString16>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { base::string16 string; @@ -764,7 +904,16 @@ void ParamTraits<base::NullableString16>::Log(const param_type& p, l->append(")"); } -void ParamTraits<base::File::Info>::Write(Message* m, +void ParamTraits<base::File::Info>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + GetParamSize(sizer, p.size); + GetParamSize(sizer, p.is_directory); + GetParamSize(sizer, p.last_modified.ToDoubleT()); + GetParamSize(sizer, p.last_accessed.ToDoubleT()); + GetParamSize(sizer, p.creation_time.ToDoubleT()); +} + +void ParamTraits<base::File::Info>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.size); WriteParam(m, p.is_directory); @@ -773,7 +922,7 @@ void ParamTraits<base::File::Info>::Write(Message* m, WriteParam(m, p.creation_time.ToDoubleT()); } -bool ParamTraits<base::File::Info>::Read(const Message* m, +bool ParamTraits<base::File::Info>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* p) { double last_modified, last_accessed, creation_time; @@ -804,11 +953,16 @@ void ParamTraits<base::File::Info>::Log(const param_type& p, l->append(")"); } -void ParamTraits<base::Time>::Write(Message* m, const param_type& p) { +void ParamTraits<base::Time>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddInt64(); +} + +void ParamTraits<base::Time>::Write(base::Pickle* m, const param_type& p) { ParamTraits<int64_t>::Write(m, p.ToInternalValue()); } -bool ParamTraits<base::Time>::Read(const Message* m, +bool ParamTraits<base::Time>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int64_t value; @@ -822,11 +976,16 @@ void ParamTraits<base::Time>::Log(const param_type& p, std::string* l) { ParamTraits<int64_t>::Log(p.ToInternalValue(), l); } -void ParamTraits<base::TimeDelta>::Write(Message* m, const param_type& p) { +void ParamTraits<base::TimeDelta>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddInt64(); +} + +void ParamTraits<base::TimeDelta>::Write(base::Pickle* m, const param_type& p) { ParamTraits<int64_t>::Write(m, p.ToInternalValue()); } -bool ParamTraits<base::TimeDelta>::Read(const Message* m, +bool ParamTraits<base::TimeDelta>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int64_t value; @@ -841,11 +1000,16 @@ void ParamTraits<base::TimeDelta>::Log(const param_type& p, std::string* l) { ParamTraits<int64_t>::Log(p.ToInternalValue(), l); } -void ParamTraits<base::TimeTicks>::Write(Message* m, const param_type& p) { +void ParamTraits<base::TimeTicks>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddInt64(); +} + +void ParamTraits<base::TimeTicks>::Write(base::Pickle* m, const param_type& p) { ParamTraits<int64_t>::Write(m, p.ToInternalValue()); } -bool ParamTraits<base::TimeTicks>::Read(const Message* m, +bool ParamTraits<base::TimeTicks>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int64_t value; @@ -860,7 +1024,8 @@ void ParamTraits<base::TimeTicks>::Log(const param_type& p, std::string* l) { ParamTraits<int64_t>::Log(p.ToInternalValue(), l); } -void ParamTraits<IPC::ChannelHandle>::Write(Message* m, const param_type& p) { +void ParamTraits<IPC::ChannelHandle>::Write(base::Pickle* m, + const param_type& p) { #if defined(OS_WIN) // On Windows marshalling pipe handle is not supported. DCHECK(p.pipe.handle == NULL); @@ -871,7 +1036,7 @@ void ParamTraits<IPC::ChannelHandle>::Write(Message* m, const param_type& p) { #endif } -bool ParamTraits<IPC::ChannelHandle>::Read(const Message* m, +bool ParamTraits<IPC::ChannelHandle>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return ReadParam(m, iter, &r->name) @@ -891,7 +1056,20 @@ void ParamTraits<IPC::ChannelHandle>::Log(const param_type& p, l->append(")"); } -void ParamTraits<LogData>::Write(Message* m, const param_type& p) { +void ParamTraits<LogData>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + GetParamSize(sizer, p.channel); + GetParamSize(sizer, p.routing_id); + GetParamSize(sizer, p.type); + GetParamSize(sizer, p.flags); + GetParamSize(sizer, p.sent); + GetParamSize(sizer, p.receive); + GetParamSize(sizer, p.dispatch); + GetParamSize(sizer, p.message_name); + GetParamSize(sizer, p.params); +} + +void ParamTraits<LogData>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.channel); WriteParam(m, p.routing_id); WriteParam(m, p.type); @@ -903,7 +1081,7 @@ void ParamTraits<LogData>::Write(Message* m, const param_type& p) { WriteParam(m, p.params); } -bool ParamTraits<LogData>::Read(const Message* m, +bool ParamTraits<LogData>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return @@ -922,7 +1100,7 @@ void ParamTraits<LogData>::Log(const param_type& p, std::string* l) { // Doesn't make sense to implement this! } -void ParamTraits<Message>::Write(Message* m, const Message& p) { +void ParamTraits<Message>::Write(base::Pickle* m, const Message& p) { #if defined(OS_POSIX) // We don't serialize the file descriptors in the nested message, so there // better not be any. @@ -945,7 +1123,7 @@ void ParamTraits<Message>::Write(Message* m, const Message& p) { m->WriteData(p.payload(), static_cast<uint32_t>(p.payload_size())); } -bool ParamTraits<Message>::Read(const Message* m, +bool ParamTraits<Message>::Read(const base::Pickle* m, base::PickleIterator* iter, Message* r) { uint32_t routing_id, type, flags; @@ -968,13 +1146,18 @@ void ParamTraits<Message>::Log(const Message& p, std::string* l) { } #if defined(OS_WIN) +void ParamTraits<HANDLE>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddInt(); +} + // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64 // bit systems. That's why we use the Windows macros to convert to 32 bits. -void ParamTraits<HANDLE>::Write(Message* m, const param_type& p) { +void ParamTraits<HANDLE>::Write(base::Pickle* m, const param_type& p) { m->WriteInt(HandleToLong(p)); } -bool ParamTraits<HANDLE>::Read(const Message* m, +bool ParamTraits<HANDLE>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int32_t temp; @@ -988,11 +1171,16 @@ void ParamTraits<HANDLE>::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("0x%p", p)); } -void ParamTraits<LOGFONT>::Write(Message* m, const param_type& p) { +void ParamTraits<LOGFONT>::GetSize(base::PickleSizer* sizer, + const param_type& p) { + sizer->AddData(sizeof(LOGFONT)); +} + +void ParamTraits<LOGFONT>::Write(base::Pickle* m, const param_type& p) { m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT)); } -bool ParamTraits<LOGFONT>::Read(const Message* m, +bool ParamTraits<LOGFONT>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; @@ -1013,11 +1201,15 @@ void ParamTraits<LOGFONT>::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("<LOGFONT>")); } -void ParamTraits<MSG>::Write(Message* m, const param_type& p) { +void ParamTraits<MSG>::GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddData(sizeof(MSG)); +} + +void ParamTraits<MSG>::Write(base::Pickle* m, const param_type& p) { m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG)); } -bool ParamTraits<MSG>::Read(const Message* m, +bool ParamTraits<MSG>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { const char *data; diff --git a/chromium/ipc/ipc_message_utils.h b/chromium/ipc/ipc_message_utils.h index 69ea7cb6d8a..cf4fa8fb14c 100644 --- a/chromium/ipc/ipc_message_utils.h +++ b/chromium/ipc/ipc_message_utils.h @@ -13,6 +13,7 @@ #include <map> #include <set> #include <string> +#include <tuple> #include <vector> #include "base/containers/small_map.h" @@ -24,36 +25,12 @@ #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" -#include "base/tuple.h" #include "build/build_config.h" #include "ipc/brokerable_attachment.h" #include "ipc/ipc_message_start.h" #include "ipc/ipc_param_traits.h" #include "ipc/ipc_sync_message.h" -#if defined(COMPILER_GCC) -// GCC "helpfully" tries to inline template methods in release mode. Except we -// want the majority of the template junk being expanded once in the -// implementation file (and only provide the definitions in -// ipc_message_utils_impl.h in those files) and exported, instead of expanded -// at every call site. Special note: GCC happily accepts the attribute before -// the method declaration, but only acts on it if it is after. -#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40500 -// Starting in gcc 4.5, the noinline no longer implies the concept covered by -// the introduced noclone attribute, which will create specialized versions of -// functions/methods when certain types are constant. -// www.gnu.org/software/gcc/gcc-4.5/changes.html -#define IPC_MSG_NOINLINE __attribute__((noinline, noclone)); -#else -#define IPC_MSG_NOINLINE __attribute__((noinline)); -#endif -#elif defined(COMPILER_MSVC) -// MSVC++ doesn't do this. -#define IPC_MSG_NOINLINE -#else -#error "Please add the noinline property for your new compiler here." -#endif - namespace base { class DictionaryValue; class FilePath; @@ -77,6 +54,7 @@ struct ChannelHandle; // How we send IPC message logs across channels. struct IPC_EXPORT LogData { LogData(); + LogData(const LogData& other); ~LogData(); std::string channel; @@ -99,15 +77,36 @@ struct IPC_EXPORT LogData { struct NoParams { }; +// Specializations are checked by 'IPC checker' part of find-bad-constructs +// Clang plugin (see WriteParam() below for the details). +template <typename... Ts> +struct CheckedTuple { + typedef std::tuple<Ts...> Tuple; +}; + +template <class P> +static inline void GetParamSize(base::PickleSizer* sizer, const P& p) { + typedef typename SimilarTypeTraits<P>::Type Type; + ParamTraits<Type>::GetSize(sizer, static_cast<const Type&>(p)); +} + +// This function is checked by 'IPC checker' part of find-bad-constructs +// Clang plugin to make it's not called on the following types: +// 1. long / unsigned long (but not typedefs to) +// 2. intmax_t, uintmax_t, intptr_t, uintptr_t, wint_t, +// size_t, rsize_t, ssize_t, ptrdiff_t, dev_t, off_t, clock_t, +// time_t, suseconds_t (including typedefs to) +// 3. Any template referencing types above (e.g. std::vector<size_t>) template <class P> -static inline void WriteParam(Message* m, const P& p) { +static inline void WriteParam(base::Pickle* m, const P& p) { typedef typename SimilarTypeTraits<P>::Type Type; ParamTraits<Type>::Write(m, static_cast<const Type& >(p)); } template <class P> -static inline bool WARN_UNUSED_RESULT -ReadParam(const Message* m, base::PickleIterator* iter, P* p) { +static inline bool WARN_UNUSED_RESULT ReadParam(const base::Pickle* m, + base::PickleIterator* iter, + P* p) { typedef typename SimilarTypeTraits<P>::Type Type; return ParamTraits<Type>::Read(m, iter, reinterpret_cast<Type* >(p)); } @@ -123,10 +122,11 @@ static inline void LogParam(const P& p, std::string* l) { template <> struct ParamTraits<bool> { typedef bool param_type; - static void Write(Message* m, const param_type& p) { - m->WriteBool(p); + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddBool(); } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { m->WriteBool(p); } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadBool(r); @@ -137,24 +137,31 @@ struct ParamTraits<bool> { template <> struct IPC_EXPORT ParamTraits<signed char> { typedef signed char param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<unsigned char> { typedef unsigned char param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; template <> struct IPC_EXPORT ParamTraits<unsigned short> { typedef unsigned short param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -163,10 +170,11 @@ struct IPC_EXPORT ParamTraits<unsigned short> { template <> struct ParamTraits<int> { typedef int param_type; - static void Write(Message* m, const param_type& p) { - m->WriteInt(p); + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddInt(); } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { m->WriteInt(p); } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadInt(r); @@ -177,10 +185,11 @@ struct ParamTraits<int> { template <> struct ParamTraits<unsigned int> { typedef unsigned int param_type; - static void Write(Message* m, const param_type& p) { - m->WriteInt(p); + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddInt(); } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { m->WriteInt(p); } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadInt(reinterpret_cast<int*>(r)); @@ -188,13 +197,29 @@ struct ParamTraits<unsigned int> { IPC_EXPORT static void Log(const param_type& p, std::string* l); }; +// long isn't safe to send over IPC because it's 4 bytes on 32 bit builds but +// 8 bytes on 64 bit builds. So if a 32 bit and 64 bit process have a channel +// that would cause problem. +// We need to keep this on for a few configs: +// 1) Windows because DWORD is typedef'd to it, which is fine because we have +// very few IPCs that cross this boundary. +// 2) We also need to keep it for Linux for two reasons: int64_t is typedef'd +// to long, and gfx::PluginWindow is long and is used in one GPU IPC. +// 3) Android 64 bit also has int64_t typedef'd to long. +// Since we want to support Android 32<>64 bit IPC, as long as we don't have +// these traits for 32 bit ARM then that'll catch any errors. +#if defined(OS_WIN) || defined(OS_LINUX) || \ + (defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS)) template <> struct ParamTraits<long> { typedef long param_type; - static void Write(Message* m, const param_type& p) { - m->WriteLongUsingDangerousNonPortableLessPersistableForm(p); + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddLong(); + } + static void Write(base::Pickle* m, const param_type& p) { + m->WriteLong(p); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadLong(r); @@ -205,24 +230,31 @@ struct ParamTraits<long> { template <> struct ParamTraits<unsigned long> { typedef unsigned long param_type; - static void Write(Message* m, const param_type& p) { - m->WriteLongUsingDangerousNonPortableLessPersistableForm(p); + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddLong(); } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { + m->WriteLong(p); + } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadLong(reinterpret_cast<long*>(r)); } IPC_EXPORT static void Log(const param_type& p, std::string* l); }; +#endif template <> struct ParamTraits<long long> { typedef long long param_type; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddInt64(); + } + static void Write(base::Pickle* m, const param_type& p) { m->WriteInt64(static_cast<int64_t>(p)); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadInt64(reinterpret_cast<int64_t*>(r)); @@ -233,10 +265,11 @@ struct ParamTraits<long long> { template <> struct ParamTraits<unsigned long long> { typedef unsigned long long param_type; - static void Write(Message* m, const param_type& p) { - m->WriteInt64(p); + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddInt64(); } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { m->WriteInt64(p); } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadInt64(reinterpret_cast<int64_t*>(r)); @@ -250,10 +283,11 @@ struct ParamTraits<unsigned long long> { template <> struct IPC_EXPORT ParamTraits<float> { typedef float param_type; - static void Write(Message* m, const param_type& p) { - m->WriteFloat(p); + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddFloat(); } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { m->WriteFloat(p); } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadFloat(r); @@ -264,8 +298,9 @@ struct IPC_EXPORT ParamTraits<float> { template <> struct IPC_EXPORT ParamTraits<double> { typedef double param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -276,10 +311,11 @@ struct IPC_EXPORT ParamTraits<double> { template <> struct ParamTraits<std::string> { typedef std::string param_type; - static void Write(Message* m, const param_type& p) { - m->WriteString(p); + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddString(p); } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { m->WriteString(p); } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadString(r); @@ -290,10 +326,13 @@ struct ParamTraits<std::string> { template <> struct ParamTraits<base::string16> { typedef base::string16 param_type; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + sizer->AddString16(p); + } + static void Write(base::Pickle* m, const param_type& p) { m->WriteString16(p); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return iter->ReadString16(r); @@ -304,8 +343,9 @@ struct ParamTraits<base::string16> { template <> struct IPC_EXPORT ParamTraits<std::vector<char> > { typedef std::vector<char> param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message*, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle*, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -314,8 +354,9 @@ struct IPC_EXPORT ParamTraits<std::vector<char> > { template <> struct IPC_EXPORT ParamTraits<std::vector<unsigned char> > { typedef std::vector<unsigned char> param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -324,8 +365,9 @@ struct IPC_EXPORT ParamTraits<std::vector<unsigned char> > { template <> struct IPC_EXPORT ParamTraits<std::vector<bool> > { typedef std::vector<bool> param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -334,12 +376,17 @@ struct IPC_EXPORT ParamTraits<std::vector<bool> > { template <class P> struct ParamTraits<std::vector<P> > { typedef std::vector<P> param_type; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, static_cast<int>(p.size())); + for (size_t i = 0; i < p.size(); i++) + GetParamSize(sizer, p[i]); + } + static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, static_cast<int>(p.size())); for (size_t i = 0; i < p.size(); i++) WriteParam(m, p[i]); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; @@ -368,13 +415,19 @@ struct ParamTraits<std::vector<P> > { template <class P> struct ParamTraits<std::set<P> > { typedef std::set<P> param_type; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, static_cast<int>(p.size())); + typename param_type::const_iterator iter; + for (iter = p.begin(); iter != p.end(); ++iter) + GetParamSize(sizer, *iter); + } + static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, static_cast<int>(p.size())); typename param_type::const_iterator iter; for (iter = p.begin(); iter != p.end(); ++iter) WriteParam(m, *iter); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; @@ -396,7 +449,15 @@ struct ParamTraits<std::set<P> > { template <class K, class V, class C, class A> struct ParamTraits<std::map<K, V, C, A> > { typedef std::map<K, V, C, A> param_type; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, static_cast<int>(p.size())); + typename param_type::const_iterator iter; + for (iter = p.begin(); iter != p.end(); ++iter) { + GetParamSize(sizer, iter->first); + GetParamSize(sizer, iter->second); + } + } + static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, static_cast<int>(p.size())); typename param_type::const_iterator iter; for (iter = p.begin(); iter != p.end(); ++iter) { @@ -404,7 +465,7 @@ struct ParamTraits<std::map<K, V, C, A> > { WriteParam(m, iter->second); } } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; @@ -428,11 +489,15 @@ struct ParamTraits<std::map<K, V, C, A> > { template <class A, class B> struct ParamTraits<std::pair<A, B> > { typedef std::pair<A, B> param_type; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, p.first); + GetParamSize(sizer, p.second); + } + static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.first); WriteParam(m, p.second); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return ReadParam(m, iter, &r->first) && ReadParam(m, iter, &r->second); @@ -450,8 +515,10 @@ struct ParamTraits<std::pair<A, B> > { template <> struct IPC_EXPORT ParamTraits<BrokerableAttachment::AttachmentId> { typedef BrokerableAttachment::AttachmentId param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; @@ -460,8 +527,9 @@ struct IPC_EXPORT ParamTraits<BrokerableAttachment::AttachmentId> { template <> struct IPC_EXPORT ParamTraits<base::DictionaryValue> { typedef base::DictionaryValue param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -486,8 +554,8 @@ struct IPC_EXPORT ParamTraits<base::DictionaryValue> { template<> struct IPC_EXPORT ParamTraits<base::FileDescriptor> { typedef base::FileDescriptor param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -498,8 +566,10 @@ struct IPC_EXPORT ParamTraits<base::FileDescriptor> { template <> struct IPC_EXPORT ParamTraits<base::SharedMemoryHandle> { typedef base::SharedMemoryHandle param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); static void Log(const param_type& p, std::string* l); }; #endif // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) @@ -507,8 +577,9 @@ struct IPC_EXPORT ParamTraits<base::SharedMemoryHandle> { template <> struct IPC_EXPORT ParamTraits<base::FilePath> { typedef base::FilePath param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -517,8 +588,9 @@ struct IPC_EXPORT ParamTraits<base::FilePath> { template <> struct IPC_EXPORT ParamTraits<base::ListValue> { typedef base::ListValue param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -527,8 +599,9 @@ struct IPC_EXPORT ParamTraits<base::ListValue> { template <> struct IPC_EXPORT ParamTraits<base::NullableString16> { typedef base::NullableString16 param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -537,8 +610,9 @@ struct IPC_EXPORT ParamTraits<base::NullableString16> { template <> struct IPC_EXPORT ParamTraits<base::File::Info> { typedef base::File::Info param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -559,8 +633,9 @@ struct SimilarTypeTraits<HWND> { template <> struct IPC_EXPORT ParamTraits<base::Time> { typedef base::Time param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -569,8 +644,9 @@ struct IPC_EXPORT ParamTraits<base::Time> { template <> struct IPC_EXPORT ParamTraits<base::TimeDelta> { typedef base::TimeDelta param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -579,19 +655,20 @@ struct IPC_EXPORT ParamTraits<base::TimeDelta> { template <> struct IPC_EXPORT ParamTraits<base::TimeTicks> { typedef base::TimeTicks param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); }; template <> -struct ParamTraits<base::Tuple<>> { - typedef base::Tuple<> param_type; - static void Write(Message* m, const param_type& p) { - } - static bool Read(const Message* m, +struct ParamTraits<std::tuple<>> { + typedef std::tuple<> param_type; + static void GetSize(base::PickleSizer* sizer, const param_type& p) {} + static void Write(base::Pickle* m, const param_type& p) {} + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { return true; @@ -601,134 +678,159 @@ struct ParamTraits<base::Tuple<>> { }; template <class A> -struct ParamTraits<base::Tuple<A>> { - typedef base::Tuple<A> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, base::get<0>(p)); +struct ParamTraits<std::tuple<A>> { + typedef std::tuple<A> param_type; + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, std::get<0>(p)); } - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p) { + WriteParam(m, std::get<0>(p)); + } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - return ReadParam(m, iter, &base::get<0>(*r)); + return ReadParam(m, iter, &std::get<0>(*r)); } static void Log(const param_type& p, std::string* l) { - LogParam(base::get<0>(p), l); + LogParam(std::get<0>(p), l); } }; template <class A, class B> -struct ParamTraits<base::Tuple<A, B>> { - typedef base::Tuple<A, B> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, base::get<0>(p)); - WriteParam(m, base::get<1>(p)); +struct ParamTraits<std::tuple<A, B>> { + typedef std::tuple<A, B> param_type; + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, std::get<0>(p)); + GetParamSize(sizer, std::get<1>(p)); + } + static void Write(base::Pickle* m, const param_type& p) { + WriteParam(m, std::get<0>(p)); + WriteParam(m, std::get<1>(p)); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - return (ReadParam(m, iter, &base::get<0>(*r)) && - ReadParam(m, iter, &base::get<1>(*r))); + return (ReadParam(m, iter, &std::get<0>(*r)) && + ReadParam(m, iter, &std::get<1>(*r))); } static void Log(const param_type& p, std::string* l) { - LogParam(base::get<0>(p), l); + LogParam(std::get<0>(p), l); l->append(", "); - LogParam(base::get<1>(p), l); + LogParam(std::get<1>(p), l); } }; template <class A, class B, class C> -struct ParamTraits<base::Tuple<A, B, C>> { - typedef base::Tuple<A, B, C> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, base::get<0>(p)); - WriteParam(m, base::get<1>(p)); - WriteParam(m, base::get<2>(p)); - } - static bool Read(const Message* m, +struct ParamTraits<std::tuple<A, B, C>> { + typedef std::tuple<A, B, C> param_type; + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, std::get<0>(p)); + GetParamSize(sizer, std::get<1>(p)); + GetParamSize(sizer, std::get<2>(p)); + } + static void Write(base::Pickle* m, const param_type& p) { + WriteParam(m, std::get<0>(p)); + WriteParam(m, std::get<1>(p)); + WriteParam(m, std::get<2>(p)); + } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - return (ReadParam(m, iter, &base::get<0>(*r)) && - ReadParam(m, iter, &base::get<1>(*r)) && - ReadParam(m, iter, &base::get<2>(*r))); + return (ReadParam(m, iter, &std::get<0>(*r)) && + ReadParam(m, iter, &std::get<1>(*r)) && + ReadParam(m, iter, &std::get<2>(*r))); } static void Log(const param_type& p, std::string* l) { - LogParam(base::get<0>(p), l); + LogParam(std::get<0>(p), l); l->append(", "); - LogParam(base::get<1>(p), l); + LogParam(std::get<1>(p), l); l->append(", "); - LogParam(base::get<2>(p), l); + LogParam(std::get<2>(p), l); } }; template <class A, class B, class C, class D> -struct ParamTraits<base::Tuple<A, B, C, D>> { - typedef base::Tuple<A, B, C, D> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, base::get<0>(p)); - WriteParam(m, base::get<1>(p)); - WriteParam(m, base::get<2>(p)); - WriteParam(m, base::get<3>(p)); - } - static bool Read(const Message* m, +struct ParamTraits<std::tuple<A, B, C, D>> { + typedef std::tuple<A, B, C, D> param_type; + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, std::get<0>(p)); + GetParamSize(sizer, std::get<1>(p)); + GetParamSize(sizer, std::get<2>(p)); + GetParamSize(sizer, std::get<3>(p)); + } + static void Write(base::Pickle* m, const param_type& p) { + WriteParam(m, std::get<0>(p)); + WriteParam(m, std::get<1>(p)); + WriteParam(m, std::get<2>(p)); + WriteParam(m, std::get<3>(p)); + } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - return (ReadParam(m, iter, &base::get<0>(*r)) && - ReadParam(m, iter, &base::get<1>(*r)) && - ReadParam(m, iter, &base::get<2>(*r)) && - ReadParam(m, iter, &base::get<3>(*r))); + return (ReadParam(m, iter, &std::get<0>(*r)) && + ReadParam(m, iter, &std::get<1>(*r)) && + ReadParam(m, iter, &std::get<2>(*r)) && + ReadParam(m, iter, &std::get<3>(*r))); } static void Log(const param_type& p, std::string* l) { - LogParam(base::get<0>(p), l); + LogParam(std::get<0>(p), l); l->append(", "); - LogParam(base::get<1>(p), l); + LogParam(std::get<1>(p), l); l->append(", "); - LogParam(base::get<2>(p), l); + LogParam(std::get<2>(p), l); l->append(", "); - LogParam(base::get<3>(p), l); + LogParam(std::get<3>(p), l); } }; template <class A, class B, class C, class D, class E> -struct ParamTraits<base::Tuple<A, B, C, D, E>> { - typedef base::Tuple<A, B, C, D, E> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, base::get<0>(p)); - WriteParam(m, base::get<1>(p)); - WriteParam(m, base::get<2>(p)); - WriteParam(m, base::get<3>(p)); - WriteParam(m, base::get<4>(p)); - } - static bool Read(const Message* m, +struct ParamTraits<std::tuple<A, B, C, D, E>> { + typedef std::tuple<A, B, C, D, E> param_type; + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, std::get<0>(p)); + GetParamSize(sizer, std::get<1>(p)); + GetParamSize(sizer, std::get<2>(p)); + GetParamSize(sizer, std::get<3>(p)); + GetParamSize(sizer, std::get<4>(p)); + } + static void Write(base::Pickle* m, const param_type& p) { + WriteParam(m, std::get<0>(p)); + WriteParam(m, std::get<1>(p)); + WriteParam(m, std::get<2>(p)); + WriteParam(m, std::get<3>(p)); + WriteParam(m, std::get<4>(p)); + } + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - return (ReadParam(m, iter, &base::get<0>(*r)) && - ReadParam(m, iter, &base::get<1>(*r)) && - ReadParam(m, iter, &base::get<2>(*r)) && - ReadParam(m, iter, &base::get<3>(*r)) && - ReadParam(m, iter, &base::get<4>(*r))); + return (ReadParam(m, iter, &std::get<0>(*r)) && + ReadParam(m, iter, &std::get<1>(*r)) && + ReadParam(m, iter, &std::get<2>(*r)) && + ReadParam(m, iter, &std::get<3>(*r)) && + ReadParam(m, iter, &std::get<4>(*r))); } static void Log(const param_type& p, std::string* l) { - LogParam(base::get<0>(p), l); + LogParam(std::get<0>(p), l); l->append(", "); - LogParam(base::get<1>(p), l); + LogParam(std::get<1>(p), l); l->append(", "); - LogParam(base::get<2>(p), l); + LogParam(std::get<2>(p), l); l->append(", "); - LogParam(base::get<3>(p), l); + LogParam(std::get<3>(p), l); l->append(", "); - LogParam(base::get<4>(p), l); + LogParam(std::get<4>(p), l); } }; template<class P> struct ParamTraits<ScopedVector<P> > { typedef ScopedVector<P> param_type; - static void Write(Message* m, const param_type& p) { + static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, static_cast<int>(p.size())); for (size_t i = 0; i < p.size(); i++) WriteParam(m, *p[i]); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size = 0; @@ -756,12 +858,17 @@ struct ParamTraits<ScopedVector<P> > { template <class P, size_t stack_capacity> struct ParamTraits<base::StackVector<P, stack_capacity> > { typedef base::StackVector<P, stack_capacity> param_type; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, static_cast<int>(p->size())); + for (size_t i = 0; i < p->size(); i++) + GetParamSize(sizer, p[i]); + } + static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, static_cast<int>(p->size())); for (size_t i = 0; i < p->size(); i++) WriteParam(m, p[i]); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; @@ -796,7 +903,15 @@ struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > { typedef base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> param_type; typedef typename param_type::key_type K; typedef typename param_type::data_type V; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + GetParamSize(sizer, static_cast<int>(p.size())); + typename param_type::const_iterator iter; + for (iter = p.begin(); iter != p.end(); ++iter) { + GetParamSize(sizer, iter->first); + GetParamSize(sizer, iter->second); + } + } + static void Write(base::Pickle* m, const param_type& p) { WriteParam(m, static_cast<int>(p.size())); typename param_type::const_iterator iter; for (iter = p.begin(); iter != p.end(); ++iter) { @@ -804,7 +919,7 @@ struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > { WriteParam(m, iter->second); } } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { int size; @@ -828,13 +943,19 @@ struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > { template <class P> struct ParamTraits<scoped_ptr<P> > { typedef scoped_ptr<P> param_type; - static void Write(Message* m, const param_type& p) { + static void GetSize(base::PickleSizer* sizer, const param_type& p) { + bool valid = !!p; + GetParamSize(sizer, valid); + if (valid) + GetParamSize(sizer, *p); + } + static void Write(base::Pickle* m, const param_type& p) { bool valid = !!p; WriteParam(m, valid); if (valid) WriteParam(m, *p); } - static bool Read(const Message* m, + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { bool valid = false; @@ -869,8 +990,8 @@ struct ParamTraits<scoped_ptr<P> > { template<> struct IPC_EXPORT ParamTraits<IPC::ChannelHandle> { typedef ChannelHandle param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -879,8 +1000,9 @@ struct IPC_EXPORT ParamTraits<IPC::ChannelHandle> { template <> struct IPC_EXPORT ParamTraits<LogData> { typedef LogData param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -888,8 +1010,8 @@ struct IPC_EXPORT ParamTraits<LogData> { template <> struct IPC_EXPORT ParamTraits<Message> { - static void Write(Message* m, const Message& p); - static bool Read(const Message* m, + static void Write(base::Pickle* m, const Message& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, Message* r); static void Log(const Message& p, std::string* l); @@ -901,8 +1023,9 @@ struct IPC_EXPORT ParamTraits<Message> { template <> struct IPC_EXPORT ParamTraits<HANDLE> { typedef HANDLE param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -911,8 +1034,9 @@ struct IPC_EXPORT ParamTraits<HANDLE> { template <> struct IPC_EXPORT ParamTraits<LOGFONT> { typedef LOGFONT param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -921,8 +1045,9 @@ struct IPC_EXPORT ParamTraits<LOGFONT> { template <> struct IPC_EXPORT ParamTraits<MSG> { typedef MSG param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, + static void GetSize(base::PickleSizer* sizer, const param_type& p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r); static void Log(const param_type& p, std::string* l); @@ -932,17 +1057,6 @@ struct IPC_EXPORT ParamTraits<MSG> { //----------------------------------------------------------------------------- // Generic message subclasses -// Used for asynchronous messages. -template <class ParamType> -class MessageSchema { - public: - typedef ParamType Param; - typedef typename base::TupleTypes<ParamType>::ParamTuple RefParam; - - static void Write(Message* msg, const RefParam& p) IPC_MSG_NOINLINE; - static bool Read(const Message* msg, Param* p) IPC_MSG_NOINLINE; -}; - // defined in ipc_logging.cc IPC_EXPORT void GenerateLogData(const std::string& channel, const Message& message, @@ -989,79 +1103,6 @@ inline void LogReplyParamsToMessage(const ReplyParamType& reply_params, inline void ConnectMessageAndReply(const Message* msg, Message* reply) {} #endif -// This class assumes that its template argument is a RefTuple (a Tuple with -// reference elements). This would go into ipc_message_utils_impl.h, but it is -// also used by chrome_frame. -template <class RefTuple> -class ParamDeserializer : public MessageReplyDeserializer { - public: - explicit ParamDeserializer(const RefTuple& out) : out_(out) { } - - bool SerializeOutputParameters(const IPC::Message& msg, - base::PickleIterator iter) override { - return ReadParam(&msg, &iter, &out_); - } - - RefTuple out_; -}; - -// Used for synchronous messages. -template <class SendParamType, class ReplyParamType> -class SyncMessageSchema { - public: - typedef SendParamType SendParam; - typedef typename base::TupleTypes<SendParam>::ParamTuple RefSendParam; - typedef ReplyParamType ReplyParam; - - static void Write(Message* msg, const RefSendParam& send) IPC_MSG_NOINLINE; - static bool ReadSendParam(const Message* msg, SendParam* p) IPC_MSG_NOINLINE; - static bool ReadReplyParam( - const Message* msg, - typename base::TupleTypes<ReplyParam>::ValueTuple* p) IPC_MSG_NOINLINE; - - template<class T, class S, class Method> - static bool DispatchWithSendParams(bool ok, const SendParam& send_params, - const Message* msg, T* obj, S* sender, - Method func) { - Message* reply = SyncMessage::GenerateReply(msg); - if (ok) { - typename base::TupleTypes<ReplyParam>::ValueTuple reply_params; - base::DispatchToMethod(obj, func, send_params, &reply_params); - WriteParam(reply, reply_params); - LogReplyParamsToMessage(reply_params, msg); - } else { - NOTREACHED() << "Error deserializing message " << msg->type(); - reply->set_reply_error(); - } - sender->Send(reply); - return ok; - } - - template<class T, class Method> - static bool DispatchDelayReplyWithSendParams(bool ok, - const SendParam& send_params, - const Message* msg, T* obj, - Method func) { - Message* reply = SyncMessage::GenerateReply(msg); - if (ok) { - base::Tuple<Message&> t = base::MakeRefTuple(*reply); - ConnectMessageAndReply(msg, reply); - base::DispatchToMethod(obj, func, send_params, &t); - } else { - NOTREACHED() << "Error deserializing message " << msg->type(); - reply->set_reply_error(); - obj->Send(reply); - } - return ok; - } - - template <typename... Ts> - static void WriteReplyParams(Message* reply, Ts... args) { - ReplyParam p(args...); - WriteParam(reply, p); - } -}; - } // namespace IPC #endif // IPC_IPC_MESSAGE_UTILS_H_ diff --git a/chromium/ipc/ipc_message_utils_impl.h b/chromium/ipc/ipc_message_utils_impl.h deleted file mode 100644 index 485dca578e9..00000000000 --- a/chromium/ipc/ipc_message_utils_impl.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// This file contains templates forward declared (but not defined) in -// ipc_message_utils.h so that they are only instantiated in certain files, -// notably a few IPC unit tests. - -#ifndef IPC_IPC_MESSAGE_UTILS_IMPL_H_ -#define IPC_IPC_MESSAGE_UTILS_IMPL_H_ - -namespace IPC { - -template <class ParamType> -void MessageSchema<ParamType>::Write(Message* msg, const RefParam& p) { - WriteParam(msg, p); -} - -template <class ParamType> -bool MessageSchema<ParamType>::Read(const Message* msg, Param* p) { - base::PickleIterator iter(*msg); - if (ReadParam(msg, &iter, p)) - return true; - NOTREACHED() << "Error deserializing message " << msg->type(); - return false; -} - -template <class SendParamType, class ReplyParamType> -void SyncMessageSchema<SendParamType, ReplyParamType>::Write( - Message* msg, - const RefSendParam& send) { - WriteParam(msg, send); -} - -template <class SendParamType, class ReplyParamType> -bool SyncMessageSchema<SendParamType, ReplyParamType>::ReadSendParam( - const Message* msg, SendParam* p) { - base::PickleIterator iter = SyncMessage::GetDataIterator(msg); - return ReadParam(msg, &iter, p); -} - -template <class SendParamType, class ReplyParamType> -bool SyncMessageSchema<SendParamType, ReplyParamType>::ReadReplyParam( - const Message* msg, typename base::TupleTypes<ReplyParam>::ValueTuple* p) { - base::PickleIterator iter = SyncMessage::GetDataIterator(msg); - return ReadParam(msg, &iter, p); -} - -} // namespace IPC - -#endif // IPC_IPC_MESSAGE_UTILS_IMPL_H_ diff --git a/chromium/ipc/ipc_message_utils_unittest.cc b/chromium/ipc/ipc_message_utils_unittest.cc index f3aa31a5160..659047d2061 100644 --- a/chromium/ipc/ipc_message_utils_unittest.cc +++ b/chromium/ipc/ipc_message_utils_unittest.cc @@ -8,6 +8,7 @@ #include <stdint.h> #include "base/files/file_path.h" +#include "base/json/json_reader.h" #include "ipc/ipc_message.h" #include "testing/gtest/include/gtest/gtest.h" @@ -90,5 +91,47 @@ TEST(IPCMessageUtilsTest, StackVector) { EXPECT_EQ(stack_vector[i], output[i]); } +// Tests that PickleSizer and Pickle agree on the size of a complex base::Value. +TEST(IPCMessageUtilsTest, ValueSize) { + scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue); + value->SetWithoutPathExpansion("foo", new base::FundamentalValue(42)); + value->SetWithoutPathExpansion("bar", new base::FundamentalValue(3.14)); + value->SetWithoutPathExpansion("baz", new base::StringValue("hello")); + value->SetWithoutPathExpansion("qux", base::Value::CreateNullValue()); + + scoped_ptr<base::DictionaryValue> nested_dict(new base::DictionaryValue); + nested_dict->SetWithoutPathExpansion("foobar", new base::FundamentalValue(5)); + value->SetWithoutPathExpansion("nested", std::move(nested_dict)); + + scoped_ptr<base::ListValue> list_value(new base::ListValue); + list_value->Append(new base::StringValue("im a string")); + list_value->Append(new base::StringValue("im another string")); + value->SetWithoutPathExpansion("awesome-list", std::move(list_value)); + + base::Pickle pickle; + IPC::WriteParam(&pickle, *value); + + base::PickleSizer sizer; + IPC::GetParamSize(&sizer, *value); + + EXPECT_EQ(sizer.payload_size(), pickle.payload_size()); +} + +TEST(IPCMessageUtilsTest, JsonValueSize) { + const char kJson[] = "[ { \"foo\": \"bar\", \"baz\": 1234.0 } ]"; + std::unique_ptr<base::Value> json_value = base::JSONReader::Read(kJson); + EXPECT_NE(nullptr, json_value); + base::ListValue value; + value.Append(std::move(json_value)); + + base::Pickle pickle; + IPC::WriteParam(&pickle, value); + + base::PickleSizer sizer; + IPC::GetParamSize(&sizer, value); + + EXPECT_EQ(sizer.payload_size(), pickle.payload_size()); +} + } // namespace } // namespace IPC diff --git a/chromium/ipc/ipc_perftest_support.cc b/chromium/ipc/ipc_perftest_support.cc index 1ecc7c740e3..5cd2b1db82a 100644 --- a/chromium/ipc/ipc_perftest_support.cc +++ b/chromium/ipc/ipc_perftest_support.cc @@ -227,6 +227,9 @@ class PerformanceChannelListener : public Listener { scoped_ptr<base::PerfTimeLogger> perf_logger_; }; +IPCChannelPerfTestBase::IPCChannelPerfTestBase() = default; +IPCChannelPerfTestBase::~IPCChannelPerfTestBase() = default; + std::vector<PingPongTestParams> IPCChannelPerfTestBase::GetDefaultTestParams() { // Test several sizes. We use 12^N for message size, and limit the message @@ -281,14 +284,14 @@ void IPCChannelPerfTestBase::RunTestChannelPingPong( void IPCChannelPerfTestBase::RunTestChannelProxyPingPong( const std::vector<PingPongTestParams>& params) { + io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart)); InitWithCustomMessageLoop("PerformanceClient", make_scoped_ptr(new base::MessageLoop())); - base::TestIOThread io_thread(base::TestIOThread::kAutoStart); // Set up IPC channel and start client. PerformanceChannelListener listener("ChannelProxy"); - CreateChannelProxy(&listener, io_thread.task_runner()); + CreateChannelProxy(&listener, io_thread_->task_runner()); listener.Init(channel_proxy()); ASSERT_TRUE(StartClient()); @@ -318,6 +321,8 @@ void IPCChannelPerfTestBase::RunTestChannelProxyPingPong( EXPECT_TRUE(WaitForClientShutdown()); DestroyChannelProxy(); + + io_thread_.reset(); } diff --git a/chromium/ipc/ipc_perftest_support.h b/chromium/ipc/ipc_perftest_support.h index 80c58d127b9..82eb1eefbf0 100644 --- a/chromium/ipc/ipc_perftest_support.h +++ b/chromium/ipc/ipc_perftest_support.h @@ -10,6 +10,8 @@ #include <vector> #include "base/macros.h" +#include "base/test/test_io_thread.h" +#include "base/thread_task_runner_handle.h" #include "build/build_config.h" #include "ipc/ipc_test_base.h" @@ -34,12 +36,24 @@ class PingPongTestParams { class IPCChannelPerfTestBase : public IPCTestBase { public: + IPCChannelPerfTestBase(); + ~IPCChannelPerfTestBase() override; + static std::vector<PingPongTestParams> GetDefaultTestParams(); void RunTestChannelPingPong( const std::vector<PingPongTestParams>& params_list); void RunTestChannelProxyPingPong( const std::vector<PingPongTestParams>& params_list); + + scoped_refptr<base::TaskRunner> io_task_runner() { + if (io_thread_) + return io_thread_->task_runner(); + return base::ThreadTaskRunnerHandle::Get(); + } + + private: + scoped_ptr<base::TestIOThread> io_thread_; }; class PingPongTestClient { diff --git a/chromium/ipc/ipc_platform_file.cc b/chromium/ipc/ipc_platform_file.cc index 97c176f3d7b..dbcfddcc779 100644 --- a/chromium/ipc/ipc_platform_file.cc +++ b/chromium/ipc/ipc_platform_file.cc @@ -11,24 +11,23 @@ namespace IPC { -PlatformFileForTransit GetFileHandleForProcess(base::PlatformFile handle, - base::ProcessHandle process, - bool close_source_handle) { - IPC::PlatformFileForTransit out_handle; +PlatformFileForTransit GetPlatformFileForTransit(base::PlatformFile handle, + bool close_source_handle) { #if defined(OS_WIN) + HANDLE raw_handle = INVALID_HANDLE_VALUE; DWORD options = DUPLICATE_SAME_ACCESS; if (close_source_handle) options |= DUPLICATE_CLOSE_SOURCE; if (handle == INVALID_HANDLE_VALUE || - !::DuplicateHandle(::GetCurrentProcess(), - handle, - process, - &out_handle, - 0, - FALSE, - options)) { - out_handle = IPC::InvalidPlatformFileForTransit(); + !::DuplicateHandle(::GetCurrentProcess(), handle, ::GetCurrentProcess(), + &raw_handle, 0, FALSE, options)) { + return IPC::InvalidPlatformFileForTransit(); } + + IPC::PlatformFileForTransit out_handle = IPC::PlatformFileForTransit( + raw_handle, base::GetCurrentProcId()); + out_handle.SetOwnershipPassesToIPC(true); + return out_handle; #elif defined(OS_POSIX) // If asked to close the source, we can simply re-use the source fd instead of // dup()ing and close()ing. @@ -39,16 +38,14 @@ PlatformFileForTransit GetFileHandleForProcess(base::PlatformFile handle, // close the source handle before the message is sent, creating a race // condition. int fd = close_source_handle ? handle : ::dup(handle); - out_handle = base::FileDescriptor(fd, true); + return base::FileDescriptor(fd, true); #else #error Not implemented. #endif - return out_handle; } -PlatformFileForTransit TakeFileHandleForProcess(base::File file, - base::ProcessHandle process) { - return GetFileHandleForProcess(file.TakePlatformFile(), process, true); +PlatformFileForTransit TakePlatformFileForTransit(base::File file) { + return GetPlatformFileForTransit(file.TakePlatformFile(), true); } } // namespace IPC diff --git a/chromium/ipc/ipc_platform_file.h b/chromium/ipc/ipc_platform_file.h index fb4d0e423de..15807f60b75 100644 --- a/chromium/ipc/ipc_platform_file.h +++ b/chromium/ipc/ipc_platform_file.h @@ -14,17 +14,24 @@ #include "base/file_descriptor_posix.h" #endif +#if defined(OS_WIN) +#include "base/memory/shared_memory_handle.h" +#endif + namespace IPC { #if defined(OS_WIN) -typedef base::PlatformFile PlatformFileForTransit; +// The semantics for IPC transfer of a SharedMemoryHandle are exactly the same +// as for a PlatformFileForTransit. The object wraps a HANDLE, and has some +// metadata that indicates the process to which the HANDLE belongs. +using PlatformFileForTransit = base::SharedMemoryHandle; #elif defined(OS_POSIX) typedef base::FileDescriptor PlatformFileForTransit; #endif inline PlatformFileForTransit InvalidPlatformFileForTransit() { #if defined(OS_WIN) - return INVALID_HANDLE_VALUE; + return PlatformFileForTransit(); #elif defined(OS_POSIX) return base::FileDescriptor(); #endif @@ -33,7 +40,7 @@ inline PlatformFileForTransit InvalidPlatformFileForTransit() { inline base::PlatformFile PlatformFileForTransitToPlatformFile( const PlatformFileForTransit& transit) { #if defined(OS_WIN) - return transit; + return transit.GetHandle(); #elif defined(OS_POSIX) return transit.fd; #endif @@ -42,23 +49,22 @@ inline base::PlatformFile PlatformFileForTransitToPlatformFile( inline base::File PlatformFileForTransitToFile( const PlatformFileForTransit& transit) { #if defined(OS_WIN) - return base::File(transit); + return base::File(transit.GetHandle()); #elif defined(OS_POSIX) return base::File(transit.fd); #endif } -// Returns a file handle equivalent to |file| that can be used in |process|. -IPC_EXPORT PlatformFileForTransit GetFileHandleForProcess( +// Creates a new handle that can be passed through IPC. The result must be +// passed to the IPC layer as part of a message, or else it will leak. +IPC_EXPORT PlatformFileForTransit GetPlatformFileForTransit( base::PlatformFile file, - base::ProcessHandle process, bool close_source_handle); -// Returns a file handle equivalent to |file| that can be used in |process|. +// Creates a new handle that can be passed through IPC. The result must be +// passed to the IPC layer as part of a message, or else it will leak. // Note that this function takes ownership of |file|. -IPC_EXPORT PlatformFileForTransit TakeFileHandleForProcess( - base::File file, - base::ProcessHandle process); +IPC_EXPORT PlatformFileForTransit TakePlatformFileForTransit(base::File file); } // namespace IPC diff --git a/chromium/ipc/ipc_send_fds_test.cc b/chromium/ipc/ipc_send_fds_test.cc index 81f589412d6..264aa855f91 100644 --- a/chromium/ipc/ipc_send_fds_test.cc +++ b/chromium/ipc/ipc_send_fds_test.cc @@ -193,6 +193,8 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) { // Enable the sandbox. char* error_buff = NULL; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED, &error_buff); bool success = (error == 0 && error_buff == NULL); @@ -200,6 +202,7 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) { return -1; sandbox_free_error(error_buff); +#pragma clang diagnostic pop // Make sure sandbox is really enabled. if (open(kDevZeroPath, O_RDONLY) != -1) { diff --git a/chromium/ipc/ipc_sync_channel.cc b/chromium/ipc/ipc_sync_channel.cc index d1942112d9a..48d9328fe1b 100644 --- a/chromium/ipc/ipc_sync_channel.cc +++ b/chromium/ipc/ipc_sync_channel.cc @@ -80,7 +80,7 @@ class SyncChannel::ReceivedSyncMsgQueue : if (!was_task_pending) { listener_task_runner_->PostTask( FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchMessagesTask, - this, scoped_refptr<SyncContext>(context))); + this, base::RetainedRef(context))); } } @@ -317,7 +317,13 @@ bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) { } else { DVLOG(1) << "Received error reply"; } - deserializers_.back().done_event->Signal(); + + base::WaitableEvent* done_event = deserializers_.back().done_event; + TRACE_EVENT_FLOW_BEGIN0( + TRACE_DISABLED_BY_DEFAULT("ipc.flow"), + "SyncChannel::SyncContext::TryToUnblockListener", done_event); + + done_event->Signal(); return true; } @@ -369,24 +375,16 @@ void SyncChannel::SyncContext::OnChannelClosed() { Context::OnChannelClosed(); } -void SyncChannel::SyncContext::OnSendTimeout(int message_id) { - base::AutoLock auto_lock(deserializers_lock_); - PendingSyncMessageQueue::iterator iter; - DVLOG(1) << "Send timeout"; - for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) { - if (iter->id == message_id) { - iter->done_event->Signal(); - break; - } - } -} - void SyncChannel::SyncContext::CancelPendingSends() { base::AutoLock auto_lock(deserializers_lock_); PendingSyncMessageQueue::iterator iter; DVLOG(1) << "Canceling pending sends"; - for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) + for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) { + TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), + "SyncChannel::SyncContext::CancelPendingSends", + iter->done_event); iter->done_event->Signal(); + } } void SyncChannel::SyncContext::OnWaitableEventSignaled(WaitableEvent* event) { @@ -503,6 +501,9 @@ bool SyncChannel::Send(Message* message) { // *this* might get deleted, so only call static functions at this point. WaitForReply(context.get(), pump_messages_event); + TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), + "SyncChannel::Send", context->GetSendDoneEvent()); + return context->Pop(); } diff --git a/chromium/ipc/ipc_sync_channel.h b/chromium/ipc/ipc_sync_channel.h index 240a28efc98..eb2a272330c 100644 --- a/chromium/ipc/ipc_sync_channel.h +++ b/chromium/ipc/ipc_sync_channel.h @@ -156,10 +156,6 @@ class IPC_EXPORT SyncChannel : public ChannelProxy { // returned. Otherwise the function returns false. bool TryToUnblockListener(const Message* msg); - // Called on the IPC thread when a sync send that runs a nested message loop - // times out. - void OnSendTimeout(int message_id); - base::WaitableEvent* shutdown_event() { return shutdown_event_; } ReceivedSyncMsgQueue* received_sync_msgs() { diff --git a/chromium/ipc/ipc_sync_channel_unittest.cc b/chromium/ipc/ipc_sync_channel_unittest.cc index 21ebafb638c..e3a71927a9b 100644 --- a/chromium/ipc/ipc_sync_channel_unittest.cc +++ b/chromium/ipc/ipc_sync_channel_unittest.cc @@ -39,16 +39,18 @@ namespace { class Worker : public Listener, public Sender { public: // Will create a channel without a name. - Worker(Channel::Mode mode, const std::string& thread_name) + Worker(Channel::Mode mode, + const std::string& thread_name, + const std::string& channel_name) : done_(new WaitableEvent(false, false)), channel_created_(new WaitableEvent(false, false)), + channel_name_(channel_name), mode_(mode), ipc_thread_((thread_name + "_ipc").c_str()), listener_thread_((thread_name + "_listener").c_str()), overrided_thread_(NULL), shutdown_event_(true, false), - is_shutdown_(false) { - } + is_shutdown_(false) {} // Will create a named channel and use this name for the threads' name. Worker(const std::string& channel_name, Channel::Mode mode) @@ -276,9 +278,9 @@ class IPCSyncChannelTest : public testing::Test { class SimpleServer : public Worker { public: - explicit SimpleServer(bool pump_during_send) - : Worker(Channel::MODE_SERVER, "simpler_server"), - pump_during_send_(pump_during_send) { } + SimpleServer(bool pump_during_send, const std::string& channel_name) + : Worker(Channel::MODE_SERVER, "simpler_server", channel_name), + pump_during_send_(pump_during_send) {} void Run() override { SendAnswerToLife(pump_during_send_, true); Done(); @@ -289,7 +291,8 @@ class SimpleServer : public Worker { class SimpleClient : public Worker { public: - SimpleClient() : Worker(Channel::MODE_CLIENT, "simple_client") { } + explicit SimpleClient(const std::string& channel_name) + : Worker(Channel::MODE_CLIENT, "simple_client", channel_name) {} void OnAnswer(int* answer) override { *answer = 42; @@ -299,8 +302,8 @@ class SimpleClient : public Worker { void Simple(bool pump_during_send) { std::vector<Worker*> workers; - workers.push_back(new SimpleServer(pump_during_send)); - workers.push_back(new SimpleClient()); + workers.push_back(new SimpleServer(pump_during_send, "Simple")); + workers.push_back(new SimpleClient("Simple")); RunTest(workers); } @@ -322,9 +325,9 @@ TEST_F(IPCSyncChannelTest, MAYBE_Simple) { // ChannelProxy::Init separately) process. class TwoStepServer : public Worker { public: - explicit TwoStepServer(bool create_pipe_now) - : Worker(Channel::MODE_SERVER, "simpler_server"), - create_pipe_now_(create_pipe_now) { } + TwoStepServer(bool create_pipe_now, const std::string& channel_name) + : Worker(Channel::MODE_SERVER, "simpler_server", channel_name), + create_pipe_now_(create_pipe_now) {} void Run() override { SendAnswerToLife(false, true); @@ -345,9 +348,9 @@ class TwoStepServer : public Worker { class TwoStepClient : public Worker { public: - TwoStepClient(bool create_pipe_now) - : Worker(Channel::MODE_CLIENT, "simple_client"), - create_pipe_now_(create_pipe_now) { } + TwoStepClient(bool create_pipe_now, const std::string& channel_name) + : Worker(Channel::MODE_CLIENT, "simple_client", channel_name), + create_pipe_now_(create_pipe_now) {} void OnAnswer(int* answer) override { *answer = 42; @@ -368,8 +371,8 @@ class TwoStepClient : public Worker { void TwoStep(bool create_server_pipe_now, bool create_client_pipe_now) { std::vector<Worker*> workers; - workers.push_back(new TwoStepServer(create_server_pipe_now)); - workers.push_back(new TwoStepClient(create_client_pipe_now)); + workers.push_back(new TwoStepServer(create_server_pipe_now, "TwoStep")); + workers.push_back(new TwoStepClient(create_client_pipe_now, "TwoStep")); RunTest(workers); } @@ -386,7 +389,8 @@ TEST_F(IPCSyncChannelTest, TwoStepInitialization) { class DelayClient : public Worker { public: - DelayClient() : Worker(Channel::MODE_CLIENT, "delay_client") { } + explicit DelayClient(const std::string& channel_name) + : Worker(Channel::MODE_CLIENT, "delay_client", channel_name) {} void OnAnswerDelay(Message* reply_msg) override { SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42); @@ -397,8 +401,8 @@ class DelayClient : public Worker { void DelayReply(bool pump_during_send) { std::vector<Worker*> workers; - workers.push_back(new SimpleServer(pump_during_send)); - workers.push_back(new DelayClient()); + workers.push_back(new SimpleServer(pump_during_send, "DelayReply")); + workers.push_back(new DelayClient("DelayReply")); RunTest(workers); } @@ -412,10 +416,12 @@ TEST_F(IPCSyncChannelTest, DelayReply) { class NoHangServer : public Worker { public: - NoHangServer(WaitableEvent* got_first_reply, bool pump_during_send) - : Worker(Channel::MODE_SERVER, "no_hang_server"), + NoHangServer(WaitableEvent* got_first_reply, + bool pump_during_send, + const std::string& channel_name) + : Worker(Channel::MODE_SERVER, "no_hang_server", channel_name), got_first_reply_(got_first_reply), - pump_during_send_(pump_during_send) { } + pump_during_send_(pump_during_send) {} void Run() override { SendAnswerToLife(pump_during_send_, true); got_first_reply_->Signal(); @@ -430,9 +436,9 @@ class NoHangServer : public Worker { class NoHangClient : public Worker { public: - explicit NoHangClient(WaitableEvent* got_first_reply) - : Worker(Channel::MODE_CLIENT, "no_hang_client"), - got_first_reply_(got_first_reply) { } + NoHangClient(WaitableEvent* got_first_reply, const std::string& channel_name) + : Worker(Channel::MODE_CLIENT, "no_hang_client", channel_name), + got_first_reply_(got_first_reply) {} void OnAnswerDelay(Message* reply_msg) override { // Use the DELAY_REPLY macro so that we can force the reply to be sent @@ -450,8 +456,9 @@ class NoHangClient : public Worker { void NoHang(bool pump_during_send) { WaitableEvent got_first_reply(false, false); std::vector<Worker*> workers; - workers.push_back(new NoHangServer(&got_first_reply, pump_during_send)); - workers.push_back(new NoHangClient(&got_first_reply)); + workers.push_back( + new NoHangServer(&got_first_reply, pump_during_send, "NoHang")); + workers.push_back(new NoHangClient(&got_first_reply, "NoHang")); RunTest(workers); } @@ -465,10 +472,12 @@ TEST_F(IPCSyncChannelTest, NoHang) { class UnblockServer : public Worker { public: - UnblockServer(bool pump_during_send, bool delete_during_send) - : Worker(Channel::MODE_SERVER, "unblock_server"), - pump_during_send_(pump_during_send), - delete_during_send_(delete_during_send) { } + UnblockServer(bool pump_during_send, + bool delete_during_send, + const std::string& channel_name) + : Worker(Channel::MODE_SERVER, "unblock_server", channel_name), + pump_during_send_(pump_during_send), + delete_during_send_(delete_during_send) {} void Run() override { if (delete_during_send_) { // Use custom code since race conditions mean the answer may or may not be @@ -497,9 +506,9 @@ class UnblockServer : public Worker { class UnblockClient : public Worker { public: - explicit UnblockClient(bool pump_during_send) - : Worker(Channel::MODE_CLIENT, "unblock_client"), - pump_during_send_(pump_during_send) { } + UnblockClient(bool pump_during_send, const std::string& channel_name) + : Worker(Channel::MODE_CLIENT, "unblock_client", channel_name), + pump_during_send_(pump_during_send) {} void OnAnswer(int* answer) override { SendDouble(pump_during_send_, true); @@ -512,8 +521,9 @@ class UnblockClient : public Worker { void Unblock(bool server_pump, bool client_pump, bool delete_during_send) { std::vector<Worker*> workers; - workers.push_back(new UnblockServer(server_pump, delete_during_send)); - workers.push_back(new UnblockClient(client_pump)); + workers.push_back( + new UnblockServer(server_pump, delete_during_send, "Unblock")); + workers.push_back(new UnblockClient(client_pump, "Unblock")); RunTest(workers); } @@ -544,10 +554,14 @@ TEST_F(IPCSyncChannelTest, MAYBE_ChannelDeleteDuringSend) { class RecursiveServer : public Worker { public: - RecursiveServer(bool expected_send_result, bool pump_first, bool pump_second) - : Worker(Channel::MODE_SERVER, "recursive_server"), + RecursiveServer(bool expected_send_result, + bool pump_first, + bool pump_second, + const std::string& channel_name) + : Worker(Channel::MODE_SERVER, "recursive_server", channel_name), expected_send_result_(expected_send_result), - pump_first_(pump_first), pump_second_(pump_second) {} + pump_first_(pump_first), + pump_second_(pump_second) {} void Run() override { SendDouble(pump_first_, expected_send_result_); Done(); @@ -563,9 +577,12 @@ class RecursiveServer : public Worker { class RecursiveClient : public Worker { public: - RecursiveClient(bool pump_during_send, bool close_channel) - : Worker(Channel::MODE_CLIENT, "recursive_client"), - pump_during_send_(pump_during_send), close_channel_(close_channel) {} + RecursiveClient(bool pump_during_send, + bool close_channel, + const std::string& channel_name) + : Worker(Channel::MODE_CLIENT, "recursive_client", channel_name), + pump_during_send_(pump_during_send), + close_channel_(close_channel) {} void OnDoubleDelay(int in, Message* reply_msg) override { SendDouble(pump_during_send_, !close_channel_); @@ -594,9 +611,9 @@ class RecursiveClient : public Worker { void Recursive( bool server_pump_first, bool server_pump_second, bool client_pump) { std::vector<Worker*> workers; - workers.push_back( - new RecursiveServer(true, server_pump_first, server_pump_second)); - workers.push_back(new RecursiveClient(client_pump, false)); + workers.push_back(new RecursiveServer(true, server_pump_first, + server_pump_second, "Recursive")); + workers.push_back(new RecursiveClient(client_pump, false, "Recursive")); RunTest(workers); } @@ -617,9 +634,9 @@ TEST_F(IPCSyncChannelTest, Recursive) { void RecursiveNoHang( bool server_pump_first, bool server_pump_second, bool client_pump) { std::vector<Worker*> workers; - workers.push_back( - new RecursiveServer(false, server_pump_first, server_pump_second)); - workers.push_back(new RecursiveClient(client_pump, true)); + workers.push_back(new RecursiveServer(false, server_pump_first, + server_pump_second, "RecursiveNoHang")); + workers.push_back(new RecursiveClient(client_pump, true, "RecursiveNoHang")); RunTest(workers); } @@ -860,8 +877,8 @@ TEST_F(IPCSyncChannelTest, QueuedReply) { class ChattyClient : public Worker { public: - ChattyClient() : - Worker(Channel::MODE_CLIENT, "chatty_client") { } + explicit ChattyClient(const std::string& channel_name) + : Worker(Channel::MODE_CLIENT, "chatty_client", channel_name) {} void OnAnswer(int* answer) override { // The PostMessage limit is 10k. Send 20% more than that. @@ -878,8 +895,8 @@ class ChattyClient : public Worker { void ChattyServer(bool pump_during_send) { std::vector<Worker*> workers; - workers.push_back(new UnblockServer(pump_during_send, false)); - workers.push_back(new ChattyClient()); + workers.push_back(new UnblockServer(pump_during_send, false, "ChattyServer")); + workers.push_back(new ChattyClient("ChattyServer")); RunTest(workers); } @@ -913,8 +930,8 @@ void TimeoutCallback() { class DoneEventRaceServer : public Worker { public: - DoneEventRaceServer() - : Worker(Channel::MODE_SERVER, "done_event_race_server") { } + explicit DoneEventRaceServer(const std::string& channel_name) + : Worker(Channel::MODE_SERVER, "done_event_race_server", channel_name) {} void Run() override { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -942,8 +959,8 @@ class DoneEventRaceServer : public Worker { // reply comes back OnObjectSignaled will be called for the first message. TEST_F(IPCSyncChannelTest, MAYBE_DoneEventRace) { std::vector<Worker*> workers; - workers.push_back(new DoneEventRaceServer()); - workers.push_back(new SimpleClient()); + workers.push_back(new DoneEventRaceServer("DoneEventRace")); + workers.push_back(new SimpleClient("DoneEventRace")); RunTest(workers); } @@ -984,8 +1001,10 @@ class TestSyncMessageFilter : public SyncMessageFilter { class SyncMessageFilterServer : public Worker { public: - SyncMessageFilterServer() - : Worker(Channel::MODE_SERVER, "sync_message_filter_server"), + explicit SyncMessageFilterServer(const std::string& channel_name) + : Worker(Channel::MODE_SERVER, + "sync_message_filter_server", + channel_name), thread_("helper_thread") { base::Thread::Options options; options.message_loop_type = base::MessageLoop::TYPE_DEFAULT; @@ -1006,10 +1025,9 @@ class SyncMessageFilterServer : public Worker { // channel does not crash after the channel has been closed. class ServerSendAfterClose : public Worker { public: - ServerSendAfterClose() - : Worker(Channel::MODE_SERVER, "simpler_server"), - send_result_(true) { - } + explicit ServerSendAfterClose(const std::string& channel_name) + : Worker(Channel::MODE_SERVER, "simpler_server", channel_name), + send_result_(true) {} bool SendDummy() { ListenerThread()->task_runner()->PostTask( @@ -1040,14 +1058,14 @@ class ServerSendAfterClose : public Worker { // Tests basic synchronous call TEST_F(IPCSyncChannelTest, SyncMessageFilter) { std::vector<Worker*> workers; - workers.push_back(new SyncMessageFilterServer()); - workers.push_back(new SimpleClient()); + workers.push_back(new SyncMessageFilterServer("SyncMessageFilter")); + workers.push_back(new SimpleClient("SyncMessageFilter")); RunTest(workers); } // Test the case when the channel is closed and a Send is attempted after that. TEST_F(IPCSyncChannelTest, SendAfterClose) { - ServerSendAfterClose server; + ServerSendAfterClose server("SendAfterClose"); server.Start(); server.done_event()->Wait(); diff --git a/chromium/ipc/ipc_sync_message_filter.cc b/chromium/ipc/ipc_sync_message_filter.cc index 1a6f6d9255a..73e905833ed 100644 --- a/chromium/ipc/ipc_sync_message_filter.cc +++ b/chromium/ipc/ipc_sync_message_filter.cc @@ -59,7 +59,10 @@ bool SyncMessageFilter::Send(Message* message) { } base::WaitableEvent* events[2] = { shutdown_event_, &done_event }; - base::WaitableEvent::WaitMany(events, 2); + if (base::WaitableEvent::WaitMany(events, 2) == 1) { + TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), + "SyncMessageFilter::Send", &done_event); + } { base::AutoLock auto_lock(lock_); @@ -103,6 +106,9 @@ bool SyncMessageFilter::OnMessageReceived(const Message& message) { (*iter)->send_result = (*iter)->deserializer->SerializeOutputParameters(message); } + TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), + "SyncMessageFilter::OnMessageReceived", + (*iter)->done_event); (*iter)->done_event->Signal(); return true; } @@ -142,6 +148,9 @@ void SyncMessageFilter::SignalAllEvents() { lock_.AssertAcquired(); for (PendingSyncMessages::iterator iter = pending_sync_messages_.begin(); iter != pending_sync_messages_.end(); ++iter) { + TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), + "SyncMessageFilter::SignalAllEvents", + (*iter)->done_event); (*iter)->done_event->Signal(); } } diff --git a/chromium/ipc/ipc_test_base.h b/chromium/ipc/ipc_test_base.h index 360188f6a5b..0646363805b 100644 --- a/chromium/ipc/ipc_test_base.h +++ b/chromium/ipc/ipc_test_base.h @@ -48,8 +48,9 @@ class IPCTestBase : public base::MultiProcessTest { // message loop on the main thread. As IPCTestBase creates IO message loop by // default, such tests need to provide a custom message loop for the main // thread. - void InitWithCustomMessageLoop(const std::string& test_client_name, - scoped_ptr<base::MessageLoop> message_loop); + virtual void InitWithCustomMessageLoop( + const std::string& test_client_name, + scoped_ptr<base::MessageLoop> message_loop); // Creates a channel with the given listener and connects to the channel // (returning true if successful), respectively. Use these to use a channel @@ -80,7 +81,7 @@ class IPCTestBase : public base::MultiProcessTest { // Starts the client process, returning true if successful; this should be // done after connecting to the channel. - bool StartClient(); + virtual bool StartClient(); #if defined(OS_POSIX) // A StartClient() variant that allows caller to pass the FD of IPC pipe @@ -91,7 +92,7 @@ class IPCTestBase : public base::MultiProcessTest { // this does not initiate client shutdown; that must be done by the test // (somehow). This must be called before the end of the test whenever // StartClient() was called successfully. - bool WaitForClientShutdown(); + virtual bool WaitForClientShutdown(); IPC::ChannelHandle GetTestChannelHandle(); @@ -104,6 +105,10 @@ class IPCTestBase : public base::MultiProcessTest { IPC::Channel* channel() { return channel_.get(); } IPC::ChannelProxy* channel_proxy() { return channel_proxy_.get(); } + void set_channel_proxy(std::unique_ptr<IPC::ChannelProxy> proxy) { + DCHECK(!channel_proxy_); + channel_proxy_.swap(proxy); + } const base::Process& client_process() const { return client_process_; } scoped_refptr<base::SequencedTaskRunner> task_runner(); diff --git a/chromium/ipc/ipc_test_sink.h b/chromium/ipc/ipc_test_sink.h index ab8531d5ea8..3e70704348e 100644 --- a/chromium/ipc/ipc_test_sink.h +++ b/chromium/ipc/ipc_test_sink.h @@ -59,17 +59,22 @@ class Message; // // class MyListener : public IPC::Listener { // public: +// MyListener(const base::Closure& closure) +// : message_received_closure_(closure) {} // virtual bool OnMessageReceived(const IPC::Message& msg) { // <do something with the message> -// MessageLoop::current()->QuitWhenIdle(); +// message_received_closure_.Run(); // return false; // to store the message in the sink, or true to drop it // } +// private: +// base::Closure message_received_closure_; // }; // -// MyListener listener; +// base::RunLoop run_loop; +// MyListener listener(run_loop.QuitClosure()); // test_sink.AddFilter(&listener); // StartSomeAsynchronousProcess(&test_sink); -// MessageLoop::current()->Run(); +// run_loop.Run(); // <inspect the results> // ... // diff --git a/chromium/ipc/ipc_tests_apk.isolate b/chromium/ipc/ipc_tests_apk.isolate index 0c0cf1c5ca7..50047a43362 100644 --- a/chromium/ipc/ipc_tests_apk.isolate +++ b/chromium/ipc/ipc_tests_apk.isolate @@ -8,6 +8,7 @@ 'variables': { 'command': [ '<(PRODUCT_DIR)/bin/run_ipc_tests', + '--logcat-output-dir', '${ISOLATED_OUTDIR}/logcats', ], 'files': [ '<(PRODUCT_DIR)/bin/run_ipc_tests', diff --git a/chromium/ipc/mach_port_attachment_mac.cc b/chromium/ipc/mach_port_attachment_mac.cc index 65baa3480ed..47fd4e98ba4 100644 --- a/chromium/ipc/mach_port_attachment_mac.cc +++ b/chromium/ipc/mach_port_attachment_mac.cc @@ -20,6 +20,9 @@ MachPortAttachmentMac::MachPortAttachmentMac(mach_port_t mach_port) << "MachPortAttachmentMac mach_port_mod_refs"; } } +MachPortAttachmentMac::MachPortAttachmentMac(mach_port_t mach_port, + FromWire from_wire) + : mach_port_(mach_port), owns_mach_port_(true) {} MachPortAttachmentMac::MachPortAttachmentMac(const WireFormat& wire_format) : BrokerableAttachment(wire_format.attachment_id), diff --git a/chromium/ipc/mach_port_attachment_mac.h b/chromium/ipc/mach_port_attachment_mac.h index 244014ed724..658cff428f9 100644 --- a/chromium/ipc/mach_port_attachment_mac.h +++ b/chromium/ipc/mach_port_attachment_mac.h @@ -51,6 +51,13 @@ class IPC_EXPORT MachPortAttachmentMac : public BrokerableAttachment { // IPC message. explicit MachPortAttachmentMac(mach_port_t mach_port); + enum FromWire { + FROM_WIRE, + }; + // This constructor takes ownership of |mach_port|, but does not modify its + // ref count. Should only be called by the receiver of a Chrome IPC message. + MachPortAttachmentMac(mach_port_t mach_port, FromWire from_wire); + // This constructor takes ownership of |wire_format.mach_port|, but does not // modify its ref count. Should only be called by the receiver of a Chrome IPC // message. diff --git a/chromium/ipc/mach_port_mac.cc b/chromium/ipc/mach_port_mac.cc index 51a5bd7abfc..9375d728eab 100644 --- a/chromium/ipc/mach_port_mac.cc +++ b/chromium/ipc/mach_port_mac.cc @@ -12,7 +12,7 @@ namespace IPC { // static -void ParamTraits<MachPortMac>::Write(Message* m, const param_type& p) { +void ParamTraits<MachPortMac>::Write(base::Pickle* m, const param_type& p) { if (!m->WriteAttachment( new IPC::internal::MachPortAttachmentMac(p.get_mach_port()))) { NOTREACHED(); @@ -20,16 +20,18 @@ void ParamTraits<MachPortMac>::Write(Message* m, const param_type& p) { } // static -bool ParamTraits<MachPortMac>::Read(const Message* m, +bool ParamTraits<MachPortMac>::Read(const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - scoped_refptr<MessageAttachment> attachment; - if (!m->ReadAttachment(iter, &attachment)) + scoped_refptr<base::Pickle::Attachment> base_attachment; + if (!m->ReadAttachment(iter, &base_attachment)) return false; + MessageAttachment* attachment = + static_cast<MessageAttachment*>(base_attachment.get()); if (attachment->GetType() != MessageAttachment::TYPE_BROKERABLE_ATTACHMENT) return false; BrokerableAttachment* brokerable_attachment = - static_cast<BrokerableAttachment*>(attachment.get()); + static_cast<BrokerableAttachment*>(attachment); if (brokerable_attachment->GetBrokerableType() != BrokerableAttachment::MACH_PORT) { return false; diff --git a/chromium/ipc/mach_port_mac.h b/chromium/ipc/mach_port_mac.h index 5c420c0fed3..b95a37b47d0 100644 --- a/chromium/ipc/mach_port_mac.h +++ b/chromium/ipc/mach_port_mac.h @@ -71,8 +71,10 @@ class IPC_EXPORT MachPortMac { template <> struct IPC_EXPORT ParamTraits<MachPortMac> { typedef MachPortMac param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* p); static void Log(const param_type& p, std::string* l); }; diff --git a/chromium/ipc/message_router.cc b/chromium/ipc/message_router.cc new file mode 100644 index 00000000000..aaf4a1f7d8d --- /dev/null +++ b/chromium/ipc/message_router.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ipc/message_router.h" + +#include "ipc/ipc_message.h" + +namespace IPC { + +MessageRouter::MessageRouter() {} + +MessageRouter::~MessageRouter() {} + +bool MessageRouter::OnControlMessageReceived(const IPC::Message& msg) { + NOTREACHED() + << "should override in subclass if you care about control messages"; + return false; +} + +bool MessageRouter::Send(IPC::Message* msg) { + NOTREACHED() + << "should override in subclass if you care about sending messages"; + return false; +} + +bool MessageRouter::AddRoute(int32_t routing_id, IPC::Listener* listener) { + if (routes_.Lookup(routing_id)) { + DLOG(ERROR) << "duplicate routing ID"; + return false; + } + routes_.AddWithID(listener, routing_id); + return true; +} + +void MessageRouter::RemoveRoute(int32_t routing_id) { + routes_.Remove(routing_id); +} + +bool MessageRouter::OnMessageReceived(const IPC::Message& msg) { + if (msg.routing_id() == MSG_ROUTING_CONTROL) + return OnControlMessageReceived(msg); + + return RouteMessage(msg); +} + +bool MessageRouter::RouteMessage(const IPC::Message& msg) { + IPC::Listener* listener = routes_.Lookup(msg.routing_id()); + if (!listener) + return false; + + return listener->OnMessageReceived(msg); +} + +} // namespace IPC diff --git a/chromium/ipc/message_router.h b/chromium/ipc/message_router.h new file mode 100644 index 00000000000..db4bc271fc9 --- /dev/null +++ b/chromium/ipc/message_router.h @@ -0,0 +1,71 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IPC_MESSAGE_ROUTER_H_ +#define IPC_MESSAGE_ROUTER_H_ + +#include <stdint.h> + +#include "base/id_map.h" +#include "base/macros.h" +#include "ipc/ipc_export.h" +#include "ipc/ipc_listener.h" +#include "ipc/ipc_sender.h" + +// The MessageRouter handles all incoming messages sent to it by routing them +// to the correct listener. Routing is based on the Message's routing ID. +// Since routing IDs are typically assigned asynchronously by the browser +// process, the MessageRouter has the notion of pending IDs for listeners that +// have not yet been assigned a routing ID. +// +// When a message arrives, the routing ID is used to index the set of routes to +// find a listener. If a listener is found, then the message is passed to it. +// Otherwise, the message is ignored if its routing ID is not equal to +// MSG_ROUTING_CONTROL. +// +// The MessageRouter supports the IPC::Sender interface for outgoing messages, +// but does not define a meaningful implementation of it. The subclass of +// MessageRouter is intended to provide that if appropriate. +// +// The MessageRouter can be used as a concrete class provided its Send method +// is not called and it does not receive any control messages. + +namespace IPC { + +class IPC_EXPORT MessageRouter : public Listener, public Sender { + public: + MessageRouter(); + ~MessageRouter() override; + + // Implemented by subclasses to handle control messages + virtual bool OnControlMessageReceived(const Message& msg); + + // Listener implementation: + bool OnMessageReceived(const Message& msg) override; + + // Like OnMessageReceived, except it only handles routed messages. Returns + // true if the message was dispatched, or false if there was no listener for + // that route id. + virtual bool RouteMessage(const Message& msg); + + // Sender implementation: + bool Send(Message* msg) override; + + // Called to add a listener for a particular message routing ID. + // Returns true if succeeded. + bool AddRoute(int32_t routing_id, Listener* listener); + + // Called to remove a listener for a particular message routing ID. + void RemoveRoute(int32_t routing_id); + + private: + // A list of all listeners with assigned routing IDs. + IDMap<Listener> routes_; + + DISALLOW_COPY_AND_ASSIGN(MessageRouter); +}; + +} // namespace IPC + +#endif // IPC_MESSAGE_ROUTER_H_ diff --git a/chromium/ipc/mojo/BUILD.gn b/chromium/ipc/mojo/BUILD.gn index 29e3a957420..22f063aaf83 100644 --- a/chromium/ipc/mojo/BUILD.gn +++ b/chromium/ipc/mojo/BUILD.gn @@ -5,17 +5,14 @@ import("//mojo/public/tools/bindings/mojom.gni") import("//testing/test.gni") -mojom("client_channel") { +mojom("mojom") { sources = [ - "client_channel.mojom", + "ipc.mojom", ] } component("mojo") { sources = [ - "async_handle_waiter.cc", - "async_handle_waiter.h", - "client_channel.mojom", "ipc_channel_mojo.cc", "ipc_channel_mojo.h", "ipc_message_pipe_reader.cc", @@ -35,35 +32,33 @@ component("mojo") { defines = [ "IPC_MOJO_IMPLEMENTATION" ] deps = [ - ":client_channel", + ":mojom", "//base", "//base/third_party/dynamic_annotations", "//ipc", - "//mojo/environment:chromium", - "//mojo/public/c/environment:environment", + "//mojo/edk/system", "//mojo/public/cpp/bindings", - "//third_party/mojo/src/mojo/edk/system", ] } test("ipc_mojo_unittests") { sources = [ - "async_handle_waiter_unittest.cc", "ipc_channel_mojo_unittest.cc", "ipc_mojo_bootstrap_unittest.cc", "run_all_unittests.cc", ] deps = [ + ":mojo", + ":mojom", "//base", "//base/test:test_support", "//base/third_party/dynamic_annotations", "//ipc", "//ipc:test_support", - "//ipc/mojo", - "//mojo/environment:chromium", + "//mojo/edk/system", + "//mojo/edk/test:test_support", "//testing/gtest", - "//third_party/mojo/src/mojo/edk/system", "//url", ] } @@ -71,18 +66,24 @@ test("ipc_mojo_unittests") { test("ipc_mojo_perftests") { sources = [ "ipc_mojo_perftest.cc", + "run_all_perftests.cc", ] deps = [ + ":mojo", + ":mojom", "//base", "//base/test:test_support", - "//base/test:test_support_perf", "//base/third_party/dynamic_annotations", "//ipc", "//ipc:test_support", - "//ipc/mojo", - "//mojo/environment:chromium", - "//third_party/mojo/src/mojo/edk/system", + "//mojo/edk/system", + "//mojo/edk/test:test_support", + "//mojo/edk/test:test_support_impl", "//url", ] + + if (is_linux && !is_component_build) { + public_configs = [ "//build/config/gcc:rpath_for_built_shared_libraries" ] + } } diff --git a/chromium/ipc/mojo/DEPS b/chromium/ipc/mojo/DEPS index 59e80a9bf82..00f925a060d 100644 --- a/chromium/ipc/mojo/DEPS +++ b/chromium/ipc/mojo/DEPS @@ -1,5 +1,5 @@ include_rules = [ "+mojo/edk/embedder", + "+mojo/edk/test", "+mojo/public", - "+third_party/mojo/src/mojo/edk/embedder", ] diff --git a/chromium/ipc/mojo/async_handle_waiter.cc b/chromium/ipc/mojo/async_handle_waiter.cc deleted file mode 100644 index 4e07480f6cf..00000000000 --- a/chromium/ipc/mojo/async_handle_waiter.cc +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/mojo/async_handle_waiter.h" - -#include "base/atomic_ref_count.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" - -namespace IPC { -namespace internal { - -class AsyncHandleWaiterContextTraits { - public: - static void Destruct(const AsyncHandleWaiter::Context* context); -}; - -// The thread-safe part of |AsyncHandleWaiter|. -// As |AsyncWait()| invokes the given callback from an arbitrary thread, -// |HandleIsReady()| and the bound |this| have to be thread-safe. -class AsyncHandleWaiter::Context - : public base::RefCountedThreadSafe<AsyncHandleWaiter::Context, - AsyncHandleWaiterContextTraits>, - public base::MessageLoopForIO::IOObserver { - public: - Context(base::WeakPtr<AsyncHandleWaiter> waiter) - : io_runner_(base::MessageLoopForIO::current()->task_runner()), - waiter_(waiter), - last_result_(MOJO_RESULT_INTERNAL), - io_loop_level_(0), - should_invoke_callback_(false) { - base::MessageLoopForIO::current()->AddIOObserver(this); - } - - void HandleIsReady(MojoResult result) { - last_result_ = result; - - // If the signaling happens in the IO handler, use |IOObserver| callback - // to invoke the callback. - if (IsCalledFromIOHandler()) { - should_invoke_callback_ = true; - return; - } - - io_runner_->PostTask(FROM_HERE, - base::Bind(&Context::InvokeWaiterCallback, this)); - } - - private: - friend void base::DeletePointer<const Context>(const Context* self); - friend class AsyncHandleWaiterContextTraits; - friend class base::RefCountedThreadSafe<Context>; - - ~Context() override { - DCHECK(base::MessageLoopForIO::current()->task_runner() == io_runner_); - base::MessageLoopForIO::current()->RemoveIOObserver(this); - } - - bool IsCalledFromIOHandler() const { - base::MessageLoop* loop = base::MessageLoop::current(); - if (!loop) - return false; - if (loop->task_runner() != io_runner_) - return false; - return io_loop_level_ > 0; - } - - // Called from |io_runner_| thus safe to touch |waiter_|. - void InvokeWaiterCallback() { - MojoResult result = last_result_; - last_result_ = MOJO_RESULT_INTERNAL; - if (waiter_) - waiter_->InvokeCallback(result); - } - - // IOObserver implementation: - - void WillProcessIOEvent() override { - DCHECK(io_loop_level_ != 0 || !should_invoke_callback_); - DCHECK_GE(io_loop_level_, 0); - io_loop_level_++; - } - - void DidProcessIOEvent() override { - // This object could have been constructed in another's class's - // DidProcessIOEvent. - if (io_loop_level_== 0) - return; - - DCHECK_GE(io_loop_level_, 1); - - // Leaving a nested loop. - if (io_loop_level_ > 1) { - io_loop_level_--; - return; - } - - // The zero |waiter_| indicates that |this| have lost the owner and can be - // under destruction. So we cannot wrap it with a |scoped_refptr| anymore. - if (!waiter_) { - should_invoke_callback_ = false; - io_loop_level_--; - return; - } - - // We have to protect |this| because |AsyncHandleWaiter| can be - // deleted during the callback. - scoped_refptr<Context> protect(this); - while (should_invoke_callback_) { - should_invoke_callback_ = false; - InvokeWaiterCallback(); - } - - io_loop_level_--; - } - - // Only |io_runner_| is accessed from arbitrary threads. Others are touched - // only from the IO thread. - const scoped_refptr<base::TaskRunner> io_runner_; - - const base::WeakPtr<AsyncHandleWaiter> waiter_; - MojoResult last_result_; - int io_loop_level_; - bool should_invoke_callback_; - - DISALLOW_COPY_AND_ASSIGN(Context); -}; - -AsyncHandleWaiter::AsyncHandleWaiter(base::Callback<void(MojoResult)> callback) - : callback_(callback), - weak_factory_(this) { - context_ = new Context(weak_factory_.GetWeakPtr()); -} - -AsyncHandleWaiter::~AsyncHandleWaiter() { -} - -MojoResult AsyncHandleWaiter::Wait(MojoHandle handle, - MojoHandleSignals signals) { - return mojo::embedder::AsyncWait( - handle, signals, base::Bind(&Context::HandleIsReady, context_)); -} - -void AsyncHandleWaiter::InvokeCallback(MojoResult result) { - callback_.Run(result); -} - -base::MessageLoopForIO::IOObserver* AsyncHandleWaiter::GetIOObserverForTest() { - return context_.get(); -} - -base::Callback<void(MojoResult)> AsyncHandleWaiter::GetWaitCallbackForTest() { - return base::Bind(&Context::HandleIsReady, context_); -} - -// static -void AsyncHandleWaiterContextTraits::Destruct( - const AsyncHandleWaiter::Context* context) { - context->io_runner_->PostTask( - FROM_HERE, - base::Bind(&base::DeletePointer<const AsyncHandleWaiter::Context>, - base::Unretained(context))); -} - -} // namespace internal -} // namespace IPC diff --git a/chromium/ipc/mojo/async_handle_waiter.h b/chromium/ipc/mojo/async_handle_waiter.h deleted file mode 100644 index e82c27ae29c..00000000000 --- a/chromium/ipc/mojo/async_handle_waiter.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_MOJO_ASYNC_HANDLE_WAITER_H_ -#define IPC_MOJO_ASYNC_HANDLE_WAITER_H_ - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "ipc/ipc_export.h" -#include "mojo/public/c/system/types.h" - -namespace IPC { -namespace internal { - -// |AsyncHandleWaiter| waits on a mojo handle asynchronously and -// invokes the given |callback| through |runner| when it is signaled. -// * To start waiting, the client must call |AsyncHandleWaiter::Wait()|. -// The client can call |Wait()| again once it is signaled and -// the |callback| is invoked. -// * To cancel waiting, delete the instance. -// -// |AsyncHandleWaiter| must be created, used and deleted only from the IO -// |thread. -class IPC_MOJO_EXPORT AsyncHandleWaiter { - public: - class Context; - - explicit AsyncHandleWaiter(base::Callback<void(MojoResult)> callback); - ~AsyncHandleWaiter(); - - MojoResult Wait(MojoHandle handle, MojoHandleSignals signals); - - base::MessageLoopForIO::IOObserver* GetIOObserverForTest(); - base::Callback<void(MojoResult)> GetWaitCallbackForTest(); - - private: - void InvokeCallback(MojoResult result); - - scoped_refptr<Context> context_; - base::Callback<void(MojoResult)> callback_; - base::WeakPtrFactory<AsyncHandleWaiter> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(AsyncHandleWaiter); -}; - -} // namespace internal -} // namespace IPC - -#endif // IPC_MOJO_ASYNC_HANDLE_WAITER_H_ diff --git a/chromium/ipc/mojo/async_handle_waiter_unittest.cc b/chromium/ipc/mojo/async_handle_waiter_unittest.cc deleted file mode 100644 index e17b4fd3b09..00000000000 --- a/chromium/ipc/mojo/async_handle_waiter_unittest.cc +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/mojo/async_handle_waiter.h" - -#include <stddef.h> -#include <stdint.h> - -#include "base/bind.h" -#include "base/location.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread.h" -#include "mojo/public/cpp/system/message_pipe.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace IPC { -namespace internal { -namespace { - -void ReadOneByteOfX(MojoHandle pipe) { - uint32_t size = 1; - char buffer = ' '; - MojoResult rv = MojoReadMessage(pipe, &buffer, &size, nullptr, nullptr, - MOJO_READ_MESSAGE_FLAG_NONE); - CHECK_EQ(rv, MOJO_RESULT_OK); - CHECK_EQ(size, 1U); - CHECK_EQ(buffer, 'X'); -} - -class AsyncHandleWaiterTest : public testing::Test { - public: - AsyncHandleWaiterTest() : worker_("test_worker") { - worker_.StartWithOptions( - base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); - } - - void SetUp() override { - message_loop_.reset(new base::MessageLoopForIO()); - ResetSignaledStates(); - mojo::CreateMessagePipe(nullptr, &pipe_to_write_, &pipe_to_read_); - target_.reset(new AsyncHandleWaiter(base::Bind( - &AsyncHandleWaiterTest::HandleIsReady, base::Unretained(this)))); - } - - protected: - MojoResult Start() { - return target_->Wait(pipe_to_read_.get().value(), - MOJO_HANDLE_SIGNAL_READABLE); - } - - void ResetSignaledStates() { - signaled_result_ = MOJO_RESULT_UNKNOWN; - run_loop_.reset(new base::RunLoop()); - } - - void WriteToPipe() { - MojoResult rv = MojoWriteMessage(pipe_to_write_.get().value(), "X", 1, - nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); - CHECK_EQ(rv, MOJO_RESULT_OK); - } - - void WriteToPipeFromWorker() { - worker_.task_runner()->PostTask( - FROM_HERE, base::Bind(&AsyncHandleWaiterTest::WriteToPipe, - base::Unretained(this))); - } - - void WaitAndAssertSignaledAndMessageIsArrived() { - run_loop_->Run(); - EXPECT_EQ(MOJO_RESULT_OK, signaled_result_); - - ReadOneByteOfX(pipe_to_read_.get().value()); - } - - void WaitAndAssertNotSignaled() { - run_loop_->RunUntilIdle(); - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(pipe_to_read_.get().value(), - MOJO_HANDLE_SIGNAL_READABLE, 0, - nullptr)); - EXPECT_EQ(MOJO_RESULT_UNKNOWN, signaled_result_); - } - - void HandleIsReady(MojoResult result) { - CHECK_EQ(base::MessageLoop::current(), message_loop_.get()); - CHECK_EQ(signaled_result_, MOJO_RESULT_UNKNOWN); - signaled_result_ = result; - run_loop_->Quit(); - } - - base::Thread worker_; - scoped_ptr<base::MessageLoop> message_loop_; - scoped_ptr<base::RunLoop> run_loop_; - mojo::ScopedMessagePipeHandle pipe_to_write_; - mojo::ScopedMessagePipeHandle pipe_to_read_; - - scoped_ptr<AsyncHandleWaiter> target_; - MojoResult signaled_result_; -}; - -TEST_F(AsyncHandleWaiterTest, SignalFromSameThread) { - EXPECT_EQ(MOJO_RESULT_OK, Start()); - WriteToPipe(); - WaitAndAssertSignaledAndMessageIsArrived(); - - // Ensures that the waiter is reusable. - ResetSignaledStates(); - - EXPECT_EQ(MOJO_RESULT_OK, Start()); - WriteToPipe(); - WaitAndAssertSignaledAndMessageIsArrived(); -} - -TEST_F(AsyncHandleWaiterTest, SignalFromDifferentThread) { - EXPECT_EQ(MOJO_RESULT_OK, Start()); - WriteToPipeFromWorker(); - WaitAndAssertSignaledAndMessageIsArrived(); - - // Ensures that the waiter is reusable. - ResetSignaledStates(); - - EXPECT_EQ(MOJO_RESULT_OK, Start()); - WriteToPipeFromWorker(); - WaitAndAssertSignaledAndMessageIsArrived(); -} - -TEST_F(AsyncHandleWaiterTest, DeleteWaiterBeforeWrite) { - EXPECT_EQ(MOJO_RESULT_OK, Start()); - - target_.reset(); - - WriteToPipe(); - WaitAndAssertNotSignaled(); -} - -TEST_F(AsyncHandleWaiterTest, DeleteWaiterBeforeSignal) { - EXPECT_EQ(MOJO_RESULT_OK, Start()); - WriteToPipe(); - - target_.reset(); - - WaitAndAssertNotSignaled(); -} - -class HandlerThatReenters { - public: - HandlerThatReenters(base::RunLoop* loop, MojoHandle handle) - : target_(nullptr), handle_(handle), loop_(loop), step_(0) {} - - void set_target(AsyncHandleWaiter* target) { target_ = target; } - - void HandleIsReady(MojoResult result) { - switch (step_) { - case 0: - RestartAndClose(result); - break; - case 1: - HandleClosingSignal(result); - break; - default: - NOTREACHED(); - break; - } - } - - void RestartAndClose(MojoResult result) { - CHECK_EQ(step_, 0); - CHECK_EQ(result, MOJO_RESULT_OK); - step_ = 1; - - ReadOneByteOfX(handle_); - target_->Wait(handle_, MOJO_HANDLE_SIGNAL_READABLE); - - // This signals the |AsyncHandleWaiter|. - MojoResult rv = MojoClose(handle_); - CHECK_EQ(rv, MOJO_RESULT_OK); - } - - void HandleClosingSignal(MojoResult result) { - CHECK_EQ(step_, 1); - CHECK_EQ(result, MOJO_RESULT_CANCELLED); - step_ = 2; - loop_->Quit(); - } - - bool IsClosingHandled() const { return step_ == 2; } - - AsyncHandleWaiter* target_; - MojoHandle handle_; - base::RunLoop* loop_; - int step_; -}; - -TEST_F(AsyncHandleWaiterTest, RestartWaitingWhileSignaled) { - HandlerThatReenters handler(run_loop_.get(), pipe_to_read_.get().value()); - target_.reset(new AsyncHandleWaiter(base::Bind( - &HandlerThatReenters::HandleIsReady, base::Unretained(&handler)))); - handler.set_target(target_.get()); - - EXPECT_EQ(MOJO_RESULT_OK, Start()); - WriteToPipe(); - run_loop_->Run(); - - EXPECT_TRUE(handler.IsClosingHandled()); - - // |HandlerThatReenters::RestartAndClose| already closed it. - ::ignore_result(pipe_to_read_.release()); -} - -class AsyncHandleWaiterIOObserverTest : public testing::Test { - public: - void SetUp() override { - message_loop_.reset(new base::MessageLoopForIO()); - target_.reset(new AsyncHandleWaiter( - base::Bind(&AsyncHandleWaiterIOObserverTest::HandleIsReady, - base::Unretained(this)))); - invocation_count_ = 0; - } - - void HandleIsReady(MojoResult result) { invocation_count_++; } - - scoped_ptr<base::MessageLoop> message_loop_; - scoped_ptr<AsyncHandleWaiter> target_; - size_t invocation_count_; -}; - -TEST_F(AsyncHandleWaiterIOObserverTest, OutsideIOEvnet) { - target_->GetWaitCallbackForTest().Run(MOJO_RESULT_OK); - EXPECT_EQ(0U, invocation_count_); - message_loop_->RunUntilIdle(); - EXPECT_EQ(1U, invocation_count_); -} - -TEST_F(AsyncHandleWaiterIOObserverTest, InsideIOEvnet) { - target_->GetIOObserverForTest()->WillProcessIOEvent(); - target_->GetWaitCallbackForTest().Run(MOJO_RESULT_OK); - EXPECT_EQ(0U, invocation_count_); - target_->GetIOObserverForTest()->DidProcessIOEvent(); - EXPECT_EQ(1U, invocation_count_); -} - -TEST_F(AsyncHandleWaiterIOObserverTest, Reenter) { - target_->GetIOObserverForTest()->WillProcessIOEvent(); - target_->GetWaitCallbackForTest().Run(MOJO_RESULT_OK); - EXPECT_EQ(0U, invocation_count_); - - // As if some other io handler start nested loop. - target_->GetIOObserverForTest()->WillProcessIOEvent(); - target_->GetWaitCallbackForTest().Run(MOJO_RESULT_OK); - target_->GetIOObserverForTest()->DidProcessIOEvent(); - EXPECT_EQ(0U, invocation_count_); - - target_->GetIOObserverForTest()->DidProcessIOEvent(); - EXPECT_EQ(1U, invocation_count_); -} - -} // namespace -} // namespace internal -} // namespace IPC diff --git a/chromium/ipc/mojo/client_channel.mojom b/chromium/ipc/mojo/client_channel.mojom deleted file mode 100644 index fd909d4ada6..00000000000 --- a/chromium/ipc/mojo/client_channel.mojom +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module IPC; - -interface ClientChannel { - Init(handle<message_pipe> pipe, int32 peer_pid) => (int32 pid); -}; diff --git a/chromium/ipc/mojo/ipc.mojom b/chromium/ipc/mojo/ipc.mojom new file mode 100644 index 00000000000..d15a23c3e95 --- /dev/null +++ b/chromium/ipc/mojo/ipc.mojom @@ -0,0 +1,31 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module IPC.mojom; + +struct SerializedHandle { + handle the_handle; + + enum Type { + MOJO_HANDLE, + WIN_HANDLE, + MACH_PORT, + }; + + Type type; +}; + +interface Channel { + Receive(array<uint8> data, array<SerializedHandle>? handles); +}; + +// An interface for connecting a pair of Channel interfaces representing a +// bidirectional IPC channel. +interface Bootstrap { + // Initializes a Chrome IPC channel over |to_client_channel| and + // |to_server_channel|. Each side also sends its PID to the other side. + Init(associated Channel& to_client_channel, + associated Channel to_server_channel, + int32 pid) => (int32 pid); +}; diff --git a/chromium/ipc/mojo/ipc_channel_mojo.cc b/chromium/ipc/mojo/ipc_channel_mojo.cc index 404c814516e..e7d0a9a33cf 100644 --- a/chromium/ipc/mojo/ipc_channel_mojo.cc +++ b/chromium/ipc/mojo/ipc_channel_mojo.cc @@ -20,177 +20,67 @@ #include "ipc/ipc_logging.h" #include "ipc/ipc_message_attachment_set.h" #include "ipc/ipc_message_macros.h" -#include "ipc/mojo/client_channel.mojom.h" #include "ipc/mojo/ipc_mojo_bootstrap.h" #include "ipc/mojo/ipc_mojo_handle_attachment.h" +#include "mojo/edk/embedder/embedder.h" #include "mojo/public/cpp/bindings/binding.h" -#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" #if defined(OS_POSIX) && !defined(OS_NACL) #include "ipc/ipc_platform_file_attachment_posix.h" #endif +#if defined(OS_MACOSX) +#include "ipc/mach_port_attachment_mac.h" +#endif + +#if defined(OS_WIN) +#include "ipc/handle_attachment_win.h" +#endif + namespace IPC { namespace { -// TODO(jam): do more tests on using channel on same thread if it supports it ( -// i.e. with use-new-edk and Windows). Also see message_pipe_dispatcher.cc -bool g_use_channel_on_io_thread_only = true; - class MojoChannelFactory : public ChannelFactory { public: - MojoChannelFactory(scoped_refptr<base::TaskRunner> io_runner, - ChannelHandle channel_handle, - Channel::Mode mode) - : io_runner_(io_runner), channel_handle_(channel_handle), mode_(mode) {} + MojoChannelFactory(mojo::ScopedMessagePipeHandle handle, Channel::Mode mode) + : handle_(std::move(handle)), mode_(mode) {} - std::string GetName() const override { - return channel_handle_.name; - } + std::string GetName() const override { return ""; } scoped_ptr<Channel> BuildChannel(Listener* listener) override { - return ChannelMojo::Create(io_runner_, channel_handle_, mode_, listener); - } - - private: - scoped_refptr<base::TaskRunner> io_runner_; - ChannelHandle channel_handle_; - Channel::Mode mode_; -}; - -//------------------------------------------------------------------------------ - -class ClientChannelMojo : public ChannelMojo, public ClientChannel { - public: - ClientChannelMojo(scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& handle, - Listener* listener) - : ChannelMojo(io_runner, handle, Channel::MODE_CLIENT, listener), - binding_(this), - weak_factory_(this) { - } - ~ClientChannelMojo() override {} - - // MojoBootstrap::Delegate implementation - void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle, - int32_t peer_pid) override { - if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { - InitMessageReader( - mojo::embedder::CreateChannel( - std::move(handle), - base::Callback<void(mojo::embedder::ChannelInfo*)>(), - scoped_refptr<base::TaskRunner>()), - peer_pid); - return; - } - CreateMessagingPipe( - std::move(handle), - base::Bind(&ClientChannelMojo::BindPipe, weak_factory_.GetWeakPtr())); - } - - // ClientChannel implementation - void Init( - mojo::ScopedMessagePipeHandle pipe, - int32_t peer_pid, - const mojo::Callback<void(int32_t)>& callback) override { - InitMessageReader(std::move(pipe), static_cast<base::ProcessId>(peer_pid)); - callback.Run(GetSelfPID()); + return ChannelMojo::Create(std::move(handle_), mode_, listener); } private: - void BindPipe(mojo::ScopedMessagePipeHandle handle) { - binding_.Bind(std::move(handle)); - } - void OnConnectionError() { - listener()->OnChannelError(); - } - - mojo::Binding<ClientChannel> binding_; - base::WeakPtrFactory<ClientChannelMojo> weak_factory_; + mojo::ScopedMessagePipeHandle handle_; + const Channel::Mode mode_; - DISALLOW_COPY_AND_ASSIGN(ClientChannelMojo); + DISALLOW_COPY_AND_ASSIGN(MojoChannelFactory); }; -//------------------------------------------------------------------------------ - -class ServerChannelMojo : public ChannelMojo { - public: - ServerChannelMojo(scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& handle, - Listener* listener) - : ChannelMojo(io_runner, handle, Channel::MODE_SERVER, listener), - weak_factory_(this) { - } - ~ServerChannelMojo() override { - Close(); - } - - // MojoBootstrap::Delegate implementation - void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle, - int32_t peer_pid) override { - if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { - message_pipe_ = mojo::embedder::CreateChannel( - std::move(handle), - base::Callback<void(mojo::embedder::ChannelInfo*)>(), - scoped_refptr<base::TaskRunner>()); - if (!message_pipe_.is_valid()) { - LOG(WARNING) << "mojo::CreateMessagePipe failed: "; - listener()->OnChannelError(); - return; - } - InitMessageReader(std::move(message_pipe_), peer_pid); - return; - } - - mojo::ScopedMessagePipeHandle peer; - MojoResult create_result = - mojo::CreateMessagePipe(nullptr, &message_pipe_, &peer); - if (create_result != MOJO_RESULT_OK) { - LOG(WARNING) << "mojo::CreateMessagePipe failed: " << create_result; - listener()->OnChannelError(); - return; - } - CreateMessagingPipe( - std::move(handle), - base::Bind(&ServerChannelMojo::InitClientChannel, - weak_factory_.GetWeakPtr(), base::Passed(&peer))); - } - // Channel override - void Close() override { - client_channel_.reset(); - message_pipe_.reset(); - ChannelMojo::Close(); - } - - private: - void InitClientChannel(mojo::ScopedMessagePipeHandle peer_handle, - mojo::ScopedMessagePipeHandle handle) { - client_channel_.Bind( - mojo::InterfacePtrInfo<ClientChannel>(std::move(handle), 0u)); - client_channel_.set_connection_error_handler(base::Bind( - &ServerChannelMojo::OnConnectionError, base::Unretained(this))); - client_channel_->Init( - std::move(peer_handle), static_cast<int32_t>(GetSelfPID()), - base::Bind(&ServerChannelMojo::ClientChannelWasInitialized, - base::Unretained(this))); - } - - void OnConnectionError() { - listener()->OnChannelError(); - } - - // ClientChannelClient implementation - void ClientChannelWasInitialized(int32_t peer_pid) { - InitMessageReader(std::move(message_pipe_), peer_pid); - } - - mojo::InterfacePtr<ClientChannel> client_channel_; - mojo::ScopedMessagePipeHandle message_pipe_; - base::WeakPtrFactory<ServerChannelMojo> weak_factory_; +mojom::SerializedHandlePtr CreateSerializedHandle( + mojo::ScopedHandle handle, + mojom::SerializedHandle::Type type) { + mojom::SerializedHandlePtr serialized_handle = mojom::SerializedHandle::New(); + serialized_handle->the_handle = std::move(handle); + serialized_handle->type = type; + return serialized_handle; +} - DISALLOW_COPY_AND_ASSIGN(ServerChannelMojo); -}; +MojoResult WrapPlatformHandle(mojo::edk::ScopedPlatformHandle handle, + mojom::SerializedHandle::Type type, + mojom::SerializedHandlePtr* serialized) { + MojoHandle wrapped_handle; + MojoResult wrap_result = mojo::edk::CreatePlatformHandleWrapper( + std::move(handle), &wrapped_handle); + if (wrap_result != MOJO_RESULT_OK) + return wrap_result; + + *serialized = CreateSerializedHandle( + mojo::MakeScopedHandle(mojo::Handle(wrapped_handle)), type); + return MOJO_RESULT_OK; +} #if defined(OS_POSIX) && !defined(OS_NACL) @@ -201,241 +91,254 @@ base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) { #endif -} // namespace - -//------------------------------------------------------------------------------ +MojoResult WrapAttachmentImpl(MessageAttachment* attachment, + mojom::SerializedHandlePtr* serialized) { + if (attachment->GetType() == MessageAttachment::TYPE_MOJO_HANDLE) { + *serialized = CreateSerializedHandle( + static_cast<internal::MojoHandleAttachment&>(*attachment).TakeHandle(), + mojom::SerializedHandle::Type::MOJO_HANDLE); + return MOJO_RESULT_OK; + } +#if defined(OS_POSIX) && !defined(OS_NACL) + if (attachment->GetType() == MessageAttachment::TYPE_PLATFORM_FILE) { + // We dup() the handles in IPC::Message to transmit. + // IPC::MessageAttachmentSet has intricate lifecycle semantics + // of FDs, so just to dup()-and-own them is the safest option. + base::ScopedFD file = TakeOrDupFile( + static_cast<IPC::internal::PlatformFileAttachment*>(attachment)); + if (!file.is_valid()) { + DPLOG(WARNING) << "Failed to dup FD to transmit."; + return MOJO_RESULT_UNKNOWN; + } -ChannelMojo::ChannelInfoDeleter::ChannelInfoDeleter( - scoped_refptr<base::TaskRunner> io_runner) - : io_runner(io_runner) { + return WrapPlatformHandle(mojo::edk::ScopedPlatformHandle( + mojo::edk::PlatformHandle(file.release())), + mojom::SerializedHandle::Type::MOJO_HANDLE, + serialized); + } +#endif +#if defined(OS_MACOSX) + DCHECK_EQ(attachment->GetType(), + MessageAttachment::TYPE_BROKERABLE_ATTACHMENT); + DCHECK_EQ(static_cast<BrokerableAttachment&>(*attachment).GetBrokerableType(), + BrokerableAttachment::MACH_PORT); + internal::MachPortAttachmentMac& mach_port_attachment = + static_cast<internal::MachPortAttachmentMac&>(*attachment); + MojoResult result = WrapPlatformHandle( + mojo::edk::ScopedPlatformHandle( + mojo::edk::PlatformHandle(mach_port_attachment.get_mach_port())), + mojom::SerializedHandle::Type::MACH_PORT, serialized); + mach_port_attachment.reset_mach_port_ownership(); + return result; +#elif defined(OS_WIN) + DCHECK_EQ(attachment->GetType(), + MessageAttachment::TYPE_BROKERABLE_ATTACHMENT); + DCHECK_EQ(static_cast<BrokerableAttachment&>(*attachment).GetBrokerableType(), + BrokerableAttachment::WIN_HANDLE); + internal::HandleAttachmentWin& handle_attachment = + static_cast<internal::HandleAttachmentWin&>(*attachment); + MojoResult result = WrapPlatformHandle( + mojo::edk::ScopedPlatformHandle( + mojo::edk::PlatformHandle(handle_attachment.get_handle())), + mojom::SerializedHandle::Type::WIN_HANDLE, serialized); + handle_attachment.reset_handle_ownership(); + return result; +#else + NOTREACHED(); + return MOJO_RESULT_UNKNOWN; +#endif // defined(OS_MACOSX) } -ChannelMojo::ChannelInfoDeleter::~ChannelInfoDeleter() { +MojoResult WrapAttachment(MessageAttachment* attachment, + mojo::Array<mojom::SerializedHandlePtr>* handles) { + mojom::SerializedHandlePtr serialized_handle; + MojoResult wrap_result = WrapAttachmentImpl(attachment, &serialized_handle); + if (wrap_result != MOJO_RESULT_OK) { + LOG(WARNING) << "Pipe failed to wrap handles. Closing: " << wrap_result; + return wrap_result; + } + handles->push_back(std::move(serialized_handle)); + return MOJO_RESULT_OK; } -void ChannelMojo::ChannelInfoDeleter::operator()( - mojo::embedder::ChannelInfo* ptr) const { - if (base::ThreadTaskRunnerHandle::Get() == io_runner) { - mojo::embedder::DestroyChannelOnIOThread(ptr); - } else { - io_runner->PostTask( - FROM_HERE, base::Bind(&mojo::embedder::DestroyChannelOnIOThread, ptr)); +MojoResult UnwrapAttachment(mojom::SerializedHandlePtr handle, + scoped_refptr<MessageAttachment>* attachment) { + if (handle->type == mojom::SerializedHandle::Type::MOJO_HANDLE) { + *attachment = + new IPC::internal::MojoHandleAttachment(std::move(handle->the_handle)); + return MOJO_RESULT_OK; + } + mojo::edk::ScopedPlatformHandle platform_handle; + MojoResult unwrap_result = mojo::edk::PassWrappedPlatformHandle( + handle->the_handle.release().value(), &platform_handle); + if (unwrap_result != MOJO_RESULT_OK) + return unwrap_result; +#if defined(OS_MACOSX) + if (handle->type == mojom::SerializedHandle::Type::MACH_PORT && + platform_handle.get().type == mojo::edk::PlatformHandle::Type::MACH) { + *attachment = new internal::MachPortAttachmentMac( + platform_handle.release().port, + internal::MachPortAttachmentMac::FROM_WIRE); + return MOJO_RESULT_OK; } +#endif // defined(OS_MACOSX) +#if defined(OS_WIN) + if (handle->type == mojom::SerializedHandle::Type::WIN_HANDLE) { + *attachment = new internal::HandleAttachmentWin( + platform_handle.release().handle, + internal::HandleAttachmentWin::FROM_WIRE); + return MOJO_RESULT_OK; + } +#endif // defined(OS_WIN) + NOTREACHED(); + return MOJO_RESULT_UNKNOWN; } -//------------------------------------------------------------------------------ +} // namespace -// static -bool ChannelMojo::ShouldBeUsed() { - // TODO(rockot): Investigate performance bottlenecks and hopefully reenable - // this at some point. http://crbug.com/500019 - return false; -} +//------------------------------------------------------------------------------ // static scoped_ptr<ChannelMojo> ChannelMojo::Create( - scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& channel_handle, + mojo::ScopedMessagePipeHandle handle, Mode mode, Listener* listener) { - switch (mode) { - case Channel::MODE_CLIENT: - return make_scoped_ptr( - new ClientChannelMojo(io_runner, channel_handle, listener)); - case Channel::MODE_SERVER: - return make_scoped_ptr( - new ServerChannelMojo(io_runner, channel_handle, listener)); - default: - NOTREACHED(); - return nullptr; - } + return make_scoped_ptr(new ChannelMojo(std::move(handle), mode, listener)); } // static scoped_ptr<ChannelFactory> ChannelMojo::CreateServerFactory( - scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& channel_handle) { + mojo::ScopedMessagePipeHandle handle) { return make_scoped_ptr( - new MojoChannelFactory(io_runner, channel_handle, Channel::MODE_SERVER)); + new MojoChannelFactory(std::move(handle), Channel::MODE_SERVER)); } // static scoped_ptr<ChannelFactory> ChannelMojo::CreateClientFactory( - scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& channel_handle) { + mojo::ScopedMessagePipeHandle handle) { return make_scoped_ptr( - new MojoChannelFactory(io_runner, channel_handle, Channel::MODE_CLIENT)); + new MojoChannelFactory(std::move(handle), Channel::MODE_CLIENT)); } -ChannelMojo::ChannelMojo(scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& handle, +ChannelMojo::ChannelMojo(mojo::ScopedMessagePipeHandle handle, Mode mode, Listener* listener) - : listener_(listener), - peer_pid_(base::kNullProcessId), - io_runner_(io_runner), - channel_info_(nullptr, ChannelInfoDeleter(nullptr)), + : pipe_(handle.get()), + listener_(listener), waiting_connect_(true), weak_factory_(this) { // Create MojoBootstrap after all members are set as it touches // ChannelMojo from a different thread. - bootstrap_ = MojoBootstrap::Create(handle, mode, this); - if (!g_use_channel_on_io_thread_only || - io_runner == base::MessageLoop::current()->task_runner()) { - InitOnIOThread(); - } else { - io_runner->PostTask(FROM_HERE, base::Bind(&ChannelMojo::InitOnIOThread, - base::Unretained(this))); - } + bootstrap_ = MojoBootstrap::Create(std::move(handle), mode, this); } ChannelMojo::~ChannelMojo() { Close(); } -void ChannelMojo::InitOnIOThread() { - ipc_support_.reset( - new ScopedIPCSupport(base::MessageLoop::current()->task_runner())); -} - -void ChannelMojo::CreateMessagingPipe( - mojo::embedder::ScopedPlatformHandle handle, - const CreateMessagingPipeCallback& callback) { - auto return_callback = base::Bind(&ChannelMojo::OnMessagingPipeCreated, - weak_factory_.GetWeakPtr(), callback); - if (!g_use_channel_on_io_thread_only || - base::ThreadTaskRunnerHandle::Get() == io_runner_) { - CreateMessagingPipeOnIOThread(std::move(handle), - base::ThreadTaskRunnerHandle::Get(), - return_callback); - } else { - io_runner_->PostTask( - FROM_HERE, - base::Bind(&ChannelMojo::CreateMessagingPipeOnIOThread, - base::Passed(&handle), base::ThreadTaskRunnerHandle::Get(), - return_callback)); - } -} - -// static -void ChannelMojo::CreateMessagingPipeOnIOThread( - mojo::embedder::ScopedPlatformHandle handle, - scoped_refptr<base::TaskRunner> callback_runner, - const CreateMessagingPipeOnIOThreadCallback& callback) { - mojo::embedder::ChannelInfo* channel_info; - mojo::ScopedMessagePipeHandle pipe = - mojo::embedder::CreateChannelOnIOThread(std::move(handle), &channel_info); - if (base::ThreadTaskRunnerHandle::Get() == callback_runner) { - callback.Run(std::move(pipe), channel_info); - } else { - callback_runner->PostTask( - FROM_HERE, base::Bind(callback, base::Passed(&pipe), channel_info)); - } -} - -void ChannelMojo::OnMessagingPipeCreated( - const CreateMessagingPipeCallback& callback, - mojo::ScopedMessagePipeHandle handle, - mojo::embedder::ChannelInfo* channel_info) { - DCHECK(!channel_info_.get()); - channel_info_ = scoped_ptr<mojo::embedder::ChannelInfo, ChannelInfoDeleter>( - channel_info, ChannelInfoDeleter(io_runner_)); - callback.Run(std::move(handle)); -} - bool ChannelMojo::Connect() { + WillConnect(); + base::AutoLock lock(lock_); + DCHECK(!task_runner_); + task_runner_ = base::ThreadTaskRunnerHandle::Get(); DCHECK(!message_reader_); - return bootstrap_->Connect(); + bootstrap_->Connect(); + return true; } void ChannelMojo::Close() { - scoped_ptr<internal::MessagePipeReader, ReaderDeleter> to_be_deleted; - + scoped_ptr<internal::MessagePipeReader, ReaderDeleter> reader; { - // |message_reader_| has to be cleared inside the lock, - // but the instance has to be deleted outside. - base::AutoLock l(lock_); - to_be_deleted = std::move(message_reader_); + base::AutoLock lock(lock_); + if (!message_reader_) + return; + // The reader's destructor may re-enter Close, so we swap it out first to + // avoid deadlock when freeing it below. + std::swap(message_reader_, reader); + // We might Close() before we Connect(). waiting_connect_ = false; } - channel_info_.reset(); - ipc_support_.reset(); - to_be_deleted.reset(); + reader.reset(); +} + +// MojoBootstrap::Delegate implementation +void ChannelMojo::OnPipesAvailable( + mojom::ChannelAssociatedPtrInfo send_channel, + mojom::ChannelAssociatedRequest receive_channel, + int32_t peer_pid) { + InitMessageReader(std::move(send_channel), std::move(receive_channel), + peer_pid); } void ChannelMojo::OnBootstrapError() { listener_->OnChannelError(); } -namespace { - -// ClosingDeleter calls |CloseWithErrorIfPending| before deleting the -// |MessagePipeReader|. -struct ClosingDeleter { - typedef std::default_delete<internal::MessagePipeReader> DefaultType; - - void operator()(internal::MessagePipeReader* ptr) const { - ptr->CloseWithErrorIfPending(); - delete ptr; - } -}; - -} // namespace - -void ChannelMojo::InitMessageReader(mojo::ScopedMessagePipeHandle pipe, - int32_t peer_pid) { - scoped_ptr<internal::MessagePipeReader, ClosingDeleter> reader( - new internal::MessagePipeReader(std::move(pipe), this)); +void ChannelMojo::InitMessageReader(mojom::ChannelAssociatedPtrInfo sender, + mojom::ChannelAssociatedRequest receiver, + base::ProcessId peer_pid) { + mojom::ChannelAssociatedPtr sender_ptr; + sender_ptr.Bind(std::move(sender)); + scoped_ptr<internal::MessagePipeReader, ChannelMojo::ReaderDeleter> reader( + new internal::MessagePipeReader(pipe_, std::move(sender_ptr), + std::move(receiver), peer_pid, this)); + bool connected = true; { - base::AutoLock l(lock_); + base::AutoLock lock(lock_); for (size_t i = 0; i < pending_messages_.size(); ++i) { - bool sent = reader->Send(make_scoped_ptr(pending_messages_[i])); - pending_messages_[i] = nullptr; - if (!sent) { - // OnChannelError() is notified through ClosingDeleter. + if (!reader->Send(std::move(pending_messages_[i]))) { + LOG(ERROR) << "Failed to flush pending messages"; pending_messages_.clear(); - LOG(ERROR) << "Failed to flush pending messages"; - return; + connected = false; + break; } } - // We set |message_reader_| here and won't get any |pending_messages_| - // hereafter. Although we might have some if there is an error, we don't - // care. They cannot be sent anyway. - message_reader_.reset(reader.release()); - pending_messages_.clear(); - waiting_connect_ = false; + if (connected) { + // We set |message_reader_| here and won't get any |pending_messages_| + // hereafter. Although we might have some if there is an error, we don't + // care. They cannot be sent anyway. + message_reader_ = std::move(reader); + pending_messages_.clear(); + waiting_connect_ = false; + } } - set_peer_pid(peer_pid); - listener_->OnChannelConnected(static_cast<int32_t>(GetPeerPID())); - if (message_reader_) - message_reader_->ReadMessagesThenWait(); -} - -void ChannelMojo::OnPipeClosed(internal::MessagePipeReader* reader) { - Close(); + if (connected) + listener_->OnChannelConnected(static_cast<int32_t>(GetPeerPID())); + else + OnPipeError(); } -void ChannelMojo::OnPipeError(internal::MessagePipeReader* reader) { - listener_->OnChannelError(); +void ChannelMojo::OnPipeError() { + DCHECK(task_runner_); + if (task_runner_->RunsTasksOnCurrentThread()) { + listener_->OnChannelError(); + } else { + task_runner_->PostTask( + FROM_HERE, + base::Bind(&ChannelMojo::OnPipeError, weak_factory_.GetWeakPtr())); + } } - -// Warning: Keep the implementation thread-safe. bool ChannelMojo::Send(Message* message) { - base::AutoLock l(lock_); + base::AutoLock lock(lock_); if (!message_reader_) { - pending_messages_.push_back(message); + pending_messages_.push_back(make_scoped_ptr(message)); // Counts as OK before the connection is established, but it's an // error otherwise. return waiting_connect_; } - return message_reader_->Send(make_scoped_ptr(message)); + if (!message_reader_->Send(make_scoped_ptr(message))) { + OnPipeError(); + return false; + } + + return true; } bool ChannelMojo::IsSendThreadSafe() const { @@ -443,17 +346,25 @@ bool ChannelMojo::IsSendThreadSafe() const { } base::ProcessId ChannelMojo::GetPeerPID() const { - return peer_pid_; + base::AutoLock lock(lock_); + if (!message_reader_) + return base::kNullProcessId; + + return message_reader_->GetPeerPid(); } base::ProcessId ChannelMojo::GetSelfPID() const { return bootstrap_->GetSelfPID(); } -void ChannelMojo::OnMessageReceived(Message& message) { +void ChannelMojo::OnMessageReceived(const Message& message) { TRACE_EVENT2("ipc,toplevel", "ChannelMojo::OnMessageReceived", "class", IPC_MESSAGE_ID_CLASS(message.type()), "line", IPC_MESSAGE_ID_LINE(message.type())); + if (AttachmentBroker* broker = AttachmentBroker::GetGlobal()) { + if (broker->OnMessageReceived(message)) + return; + } listener_->OnMessageReceived(message); if (message.dispatch_error()) listener_->OnBadMessageReceived(message); @@ -461,92 +372,64 @@ void ChannelMojo::OnMessageReceived(Message& message) { #if defined(OS_POSIX) && !defined(OS_NACL) int ChannelMojo::GetClientFileDescriptor() const { - return bootstrap_->GetClientFileDescriptor(); + return -1; } base::ScopedFD ChannelMojo::TakeClientFileDescriptor() { - return bootstrap_->TakeClientFileDescriptor(); + return base::ScopedFD(GetClientFileDescriptor()); } #endif // defined(OS_POSIX) && !defined(OS_NACL) // static MojoResult ChannelMojo::ReadFromMessageAttachmentSet( Message* message, - std::vector<MojoHandle>* handles) { - // We dup() the handles in IPC::Message to transmit. - // IPC::MessageAttachmentSet has intricate lifecycle semantics - // of FDs, so just to dup()-and-own them is the safest option. + mojo::Array<mojom::SerializedHandlePtr>* handles) { if (message->HasAttachments()) { MessageAttachmentSet* set = message->attachment_set(); for (unsigned i = 0; i < set->num_non_brokerable_attachments(); ++i) { - scoped_refptr<MessageAttachment> attachment = - set->GetNonBrokerableAttachmentAt(i); - switch (attachment->GetType()) { - case MessageAttachment::TYPE_PLATFORM_FILE: -#if defined(OS_POSIX) && !defined(OS_NACL) - { - base::ScopedFD file = - TakeOrDupFile(static_cast<IPC::internal::PlatformFileAttachment*>( - attachment.get())); - if (!file.is_valid()) { - DPLOG(WARNING) << "Failed to dup FD to transmit."; - set->CommitAllDescriptors(); - return MOJO_RESULT_UNKNOWN; - } - - MojoHandle wrapped_handle; - MojoResult wrap_result = mojo::embedder::CreatePlatformHandleWrapper( - mojo::embedder::ScopedPlatformHandle( - mojo::embedder::PlatformHandle(file.release())), - &wrapped_handle); - if (MOJO_RESULT_OK != wrap_result) { - LOG(WARNING) << "Pipe failed to wrap handles. Closing: " - << wrap_result; - set->CommitAllDescriptors(); - return wrap_result; - } - - handles->push_back(wrapped_handle); - } -#else - NOTREACHED(); -#endif // defined(OS_POSIX) && !defined(OS_NACL) - break; - case MessageAttachment::TYPE_MOJO_HANDLE: { - mojo::ScopedHandle handle = - static_cast<IPC::internal::MojoHandleAttachment*>( - attachment.get())->TakeHandle(); - handles->push_back(handle.release().value()); - } break; - case MessageAttachment::TYPE_BROKERABLE_ATTACHMENT: - // Brokerable attachments are handled by the AttachmentBroker so - // there's no need to do anything here. - NOTREACHED(); - break; + MojoResult result = WrapAttachment( + set->GetNonBrokerableAttachmentAt(i).get(), handles); + if (result != MOJO_RESULT_OK) { + set->CommitAllDescriptors(); + return result; + } + } + for (unsigned i = 0; i < set->num_brokerable_attachments(); ++i) { + MojoResult result = + WrapAttachment(set->GetBrokerableAttachmentAt(i).get(), handles); + if (result != MOJO_RESULT_OK) { + set->CommitAllDescriptors(); + return result; } } - set->CommitAllDescriptors(); } - return MOJO_RESULT_OK; } // static MojoResult ChannelMojo::WriteToMessageAttachmentSet( - const std::vector<MojoHandle>& handle_buffer, + mojo::Array<mojom::SerializedHandlePtr> handle_buffer, Message* message) { for (size_t i = 0; i < handle_buffer.size(); ++i) { + scoped_refptr<MessageAttachment> unwrapped_attachment; + MojoResult unwrap_result = UnwrapAttachment(std::move(handle_buffer[i]), + &unwrapped_attachment); + if (unwrap_result != MOJO_RESULT_OK) { + LOG(WARNING) << "Pipe failed to unwrap handles. Closing: " + << unwrap_result; + return unwrap_result; + } + DCHECK(unwrapped_attachment); + bool ok = message->attachment_set()->AddAttachment( - new IPC::internal::MojoHandleAttachment( - mojo::MakeScopedHandle(mojo::Handle(handle_buffer[i])))); + std::move(unwrapped_attachment)); DCHECK(ok); if (!ok) { LOG(ERROR) << "Failed to add new Mojo handle."; return MOJO_RESULT_UNKNOWN; } } - return MOJO_RESULT_OK; } diff --git a/chromium/ipc/mojo/ipc_channel_mojo.h b/chromium/ipc/mojo/ipc_channel_mojo.h index a5ddf1e4077..5968d84ec9b 100644 --- a/chromium/ipc/mojo/ipc_channel_mojo.h +++ b/chromium/ipc/mojo/ipc_channel_mojo.h @@ -10,43 +10,29 @@ #include <vector> #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "base/synchronization/lock.h" +#include "base/task_runner.h" #include "build/build_config.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_channel_factory.h" #include "ipc/ipc_export.h" #include "ipc/mojo/ipc_message_pipe_reader.h" #include "ipc/mojo/ipc_mojo_bootstrap.h" -#include "ipc/mojo/scoped_ipc_support.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/public/cpp/system/core.h" -#include "third_party/mojo/src/mojo/edk/embedder/channel_info_forward.h" namespace IPC { -// Mojo-based IPC::Channel implementation over a platform handle. +// Mojo-based IPC::Channel implementation over a Mojo message pipe. // -// ChannelMojo builds Mojo MessagePipe using underlying pipe given by -// "bootstrap" IPC::Channel which creates and owns platform pipe like -// named socket. The bootstrap Channel is used only for establishing -// the underlying connection. ChannelMojo takes its handle over once -// the it is made and puts MessagePipe on it. +// ChannelMojo builds a Mojo MessagePipe using the provided message pipe +// |handle| and builds an associated interface for each direction on the +// channel. // -// ChannelMojo has a couple of MessagePipes: -// -// * The first MessagePipe, which is built on top of bootstrap handle, -// is the "control" pipe. It is used to communicate out-of-band -// control messages that aren't visible from IPC::Listener. -// -// * The second MessagePipe, which is created by the server channel -// and sent to client Channel over the control pipe, is used -// to send IPC::Messages as an IPC::Sender. -// -// TODO(morrita): Extract handle creation part of IPC::Channel into -// separate class to clarify what ChannelMojo relies -// on. // TODO(morrita): Add APIs to create extra MessagePipes to let // Mojo-based objects talk over this Channel. // @@ -55,32 +41,19 @@ class IPC_MOJO_EXPORT ChannelMojo public MojoBootstrap::Delegate, public NON_EXPORTED_BASE(internal::MessagePipeReader::Delegate) { public: - using CreateMessagingPipeCallback = - base::Callback<void(mojo::ScopedMessagePipeHandle)>; - using CreateMessagingPipeOnIOThreadCallback = - base::Callback<void(mojo::ScopedMessagePipeHandle, - mojo::embedder::ChannelInfo*)>; - - // True if ChannelMojo should be used regardless of the flag. - static bool ShouldBeUsed(); - - // Create ChannelMojo. A bootstrap channel is created as well. - static scoped_ptr<ChannelMojo> Create( - scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& channel_handle, - Mode mode, - Listener* listener); + // Creates a ChannelMojo. + static scoped_ptr<ChannelMojo> Create(mojo::ScopedMessagePipeHandle handle, + Mode mode, + Listener* listener); // Create a factory object for ChannelMojo. // The factory is used to create Mojo-based ChannelProxy family. // |host| must not be null. static scoped_ptr<ChannelFactory> CreateServerFactory( - scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& channel_handle); + mojo::ScopedMessagePipeHandle handle); static scoped_ptr<ChannelFactory> CreateClientFactory( - scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& channel_handle); + mojo::ScopedMessagePipeHandle handle); ~ChannelMojo() override; @@ -100,77 +73,49 @@ class IPC_MOJO_EXPORT ChannelMojo // These access protected API of IPC::Message, which has ChannelMojo // as a friend class. static MojoResult WriteToMessageAttachmentSet( - const std::vector<MojoHandle>& handle_buffer, + mojo::Array<mojom::SerializedHandlePtr> handle_buffer, Message* message); static MojoResult ReadFromMessageAttachmentSet( Message* message, - std::vector<MojoHandle>* handles); + mojo::Array<mojom::SerializedHandlePtr>* handles); // MojoBootstrapDelegate implementation + void OnPipesAvailable(mojom::ChannelAssociatedPtrInfo send_channel, + mojom::ChannelAssociatedRequest receive_channel, + int32_t peer_pid) override; void OnBootstrapError() override; // MessagePipeReader::Delegate - void OnMessageReceived(Message& message) override; - void OnPipeClosed(internal::MessagePipeReader* reader) override; - void OnPipeError(internal::MessagePipeReader* reader) override; + void OnMessageReceived(const Message& message) override; + void OnPipeError() override; - protected: - ChannelMojo(scoped_refptr<base::TaskRunner> io_runner, - const ChannelHandle& channel_handle, + private: + ChannelMojo(mojo::ScopedMessagePipeHandle handle, Mode mode, Listener* listener); - void CreateMessagingPipe(mojo::embedder::ScopedPlatformHandle handle, - const CreateMessagingPipeCallback& callback); - void InitMessageReader(mojo::ScopedMessagePipeHandle pipe, int32_t peer_pid); - - Listener* listener() const { return listener_; } - void set_peer_pid(base::ProcessId pid) { peer_pid_ = pid; } - - private: - struct ChannelInfoDeleter { - explicit ChannelInfoDeleter(scoped_refptr<base::TaskRunner> io_runner); - ~ChannelInfoDeleter(); - - void operator()(mojo::embedder::ChannelInfo* ptr) const; - - scoped_refptr<base::TaskRunner> io_runner; - }; + void InitMessageReader(mojom::ChannelAssociatedPtrInfo sender, + mojom::ChannelAssociatedRequest receiver, + base::ProcessId peer_pid); // ChannelMojo needs to kill its MessagePipeReader in delayed manner // because the channel wants to kill these readers during the // notifications invoked by them. typedef internal::MessagePipeReader::DelayedDeleter ReaderDeleter; - void InitOnIOThread(); - - static void CreateMessagingPipeOnIOThread( - mojo::embedder::ScopedPlatformHandle handle, - scoped_refptr<base::TaskRunner> callback_runner, - const CreateMessagingPipeOnIOThreadCallback& callback); - void OnMessagingPipeCreated(const CreateMessagingPipeCallback& callback, - mojo::ScopedMessagePipeHandle handle, - mojo::embedder::ChannelInfo* channel_info); + // A TaskRunner which runs tasks on the ChannelMojo's owning thread. + scoped_refptr<base::TaskRunner> task_runner_; + const mojo::MessagePipeHandle pipe_; scoped_ptr<MojoBootstrap> bootstrap_; Listener* listener_; - base::ProcessId peer_pid_; - scoped_refptr<base::TaskRunner> io_runner_; - scoped_ptr<mojo::embedder::ChannelInfo, - ChannelInfoDeleter> channel_info_; - - // Guards |message_reader_|, |waiting_connect_| and |pending_messages_| - // - // * The contents of |pending_messages_| can be modified from any thread. - // * |message_reader_| is modified only from the IO thread, - // but they can be referenced from other threads. - base::Lock lock_; + + // Guards access to the fields below. + mutable base::Lock lock_; scoped_ptr<internal::MessagePipeReader, ReaderDeleter> message_reader_; - ScopedVector<Message> pending_messages_; + std::vector<scoped_ptr<Message>> pending_messages_; bool waiting_connect_; - scoped_ptr<ScopedIPCSupport> ipc_support_; - base::WeakPtrFactory<ChannelMojo> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ChannelMojo); diff --git a/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc b/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc index b4f4154c67c..615e72d5945 100644 --- a/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc +++ b/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc @@ -15,6 +15,7 @@ #include "base/pickle.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/test_io_thread.h" #include "base/test/test_timeouts.h" #include "base/thread_task_runner_handle.h" #include "base/threading/thread.h" @@ -22,22 +23,45 @@ #include "ipc/ipc_message.h" #include "ipc/ipc_test_base.h" #include "ipc/ipc_test_channel_listener.h" +#include "ipc/mojo/ipc_channel_mojo.h" #include "ipc/mojo/ipc_mojo_handle_attachment.h" #include "ipc/mojo/ipc_mojo_message_helper.h" #include "ipc/mojo/ipc_mojo_param_traits.h" -#include "ipc/mojo/scoped_ipc_support.h" +#include "mojo/edk/test/mojo_test_base.h" +#include "mojo/edk/test/multiprocess_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" #if defined(OS_POSIX) #include "base/file_descriptor_posix.h" #include "ipc/ipc_platform_file_attachment_posix.h" #endif +#define DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(client_name, test_base) \ + class client_name##_MainFixture : public test_base { \ + public: \ + void Main(); \ + }; \ + MULTIPROCESS_TEST_MAIN_WITH_SETUP( \ + client_name##TestChildMain, \ + ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) { \ + CHECK(!mojo::edk::test::MultiprocessTestHelper::primordial_pipe_token \ + .empty()); \ + client_name##_MainFixture test; \ + test.Init(mojo::edk::CreateChildMessagePipe( \ + mojo::edk::test::MultiprocessTestHelper::primordial_pipe_token)); \ + test.Main(); \ + return (::testing::Test::HasFatalFailure() || \ + ::testing::Test::HasNonfatalFailure()) \ + ? 1 \ + : 0; \ + } \ + void client_name##_MainFixture::Main() + namespace { class ListenerThatExpectsOK : public IPC::Listener { public: - ListenerThatExpectsOK() - : received_ok_(false) {} + ListenerThatExpectsOK() : received_ok_(false) {} ~ListenerThatExpectsOK() override {} @@ -59,8 +83,8 @@ class ListenerThatExpectsOK : public IPC::Listener { } static void SendOK(IPC::Sender* sender) { - IPC::Message* message = new IPC::Message( - 0, 2, IPC::Message::PRIORITY_NORMAL); + IPC::Message* message = + new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); message->WriteString(std::string("OK")); ASSERT_TRUE(sender->Send(message)); } @@ -71,13 +95,12 @@ class ListenerThatExpectsOK : public IPC::Listener { class ChannelClient { public: - explicit ChannelClient(IPC::Listener* listener, const char* name) { - channel_ = IPC::ChannelMojo::Create(main_message_loop_.task_runner(), - IPCTestBase::GetChannelName(name), - IPC::Channel::MODE_CLIENT, listener); + void Init(mojo::ScopedMessagePipeHandle handle) { + handle_ = std::move(handle); } - - void Connect() { + void Connect(IPC::Listener* listener) { + channel_ = IPC::ChannelMojo::Create(std::move(handle_), + IPC::Channel::MODE_CLIENT, listener); CHECK(channel_->Connect()); } @@ -94,48 +117,46 @@ class ChannelClient { private: base::MessageLoopForIO main_message_loop_; + mojo::ScopedMessagePipeHandle handle_; scoped_ptr<IPC::ChannelMojo> channel_; }; -class IPCChannelMojoTestBase : public IPCTestBase { +class IPCChannelMojoTest : public testing::Test { public: - void InitWithMojo(const std::string& test_client_name) { - Init(test_client_name); - } + IPCChannelMojoTest() : io_thread_(base::TestIOThread::Mode::kAutoStart) {} - void TearDown() override { - // Make sure Mojo IPC support is properly shutdown on the I/O loop before - // TearDown continues. - base::RunLoop run_loop; - task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure()); - run_loop.Run(); + void TearDown() override { base::RunLoop().RunUntilIdle(); } - IPCTestBase::TearDown(); + void InitWithMojo(const std::string& test_client_name) { + handle_ = helper_.StartChild(test_client_name); } -}; -class IPCChannelMojoTest : public IPCChannelMojoTestBase { - protected: - scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( - const IPC::ChannelHandle& handle, - base::SequencedTaskRunner* runner) override { - return IPC::ChannelMojo::CreateServerFactory(task_runner(), handle); + void CreateChannel(IPC::Listener* listener) { + channel_ = IPC::ChannelMojo::Create(std::move(handle_), + IPC::Channel::MODE_SERVER, listener); } - bool DidStartClient() override { - bool ok = IPCTestBase::DidStartClient(); - DCHECK(ok); - return ok; - } -}; + bool ConnectChannel() { return channel_->Connect(); } + void DestroyChannel() { channel_.reset(); } + + bool WaitForClientShutdown() { return helper_.WaitForChildTestShutdown(); } + + IPC::Sender* sender() { return channel(); } + IPC::Channel* channel() { return channel_.get(); } + + private: + base::MessageLoop message_loop_; + base::TestIOThread io_thread_; + mojo::edk::test::MultiprocessTestHelper helper_; + mojo::ScopedMessagePipeHandle handle_; + scoped_ptr<IPC::Channel> channel_; +}; class TestChannelListenerWithExtraExpectations : public IPC::TestChannelListener { public: - TestChannelListenerWithExtraExpectations() - : is_connected_called_(false) { - } + TestChannelListenerWithExtraExpectations() : is_connected_called_(false) {} void OnChannelConnected(int32_t peer_pid) override { IPC::TestChannelListener::OnChannelConnected(peer_pid); @@ -163,15 +184,12 @@ TEST_F(IPCChannelMojoTest, MAYBE_ConnectedFromClient) { CreateChannel(&listener); listener.Init(sender()); ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); - IPC::TestChannelListener::SendOneMessage( - sender(), "hello from parent"); + IPC::TestChannelListener::SendOneMessage(sender(), "hello from parent"); base::MessageLoop::current()->Run(); - EXPECT_TRUE(base::kNullProcessId != this->channel()->GetPeerPID()); - this->channel()->Close(); + channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); EXPECT_TRUE(listener.is_connected_called()); @@ -181,28 +199,22 @@ TEST_F(IPCChannelMojoTest, MAYBE_ConnectedFromClient) { } // A long running process that connects to us -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) { +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestClient, ChannelClient) { TestChannelListenerWithExtraExpectations listener; - ChannelClient client(&listener, "IPCChannelMojoTestClient"); - client.Connect(); - listener.Init(client.channel()); + Connect(&listener); + listener.Init(channel()); - IPC::TestChannelListener::SendOneMessage( - client.channel(), "hello from child"); + IPC::TestChannelListener::SendOneMessage(channel(), "hello from child"); base::MessageLoop::current()->Run(); EXPECT_TRUE(listener.is_connected_called()); EXPECT_TRUE(listener.HasSentAll()); - client.Close(); - - return 0; + Close(); } class ListenerExpectingErrors : public IPC::Listener { public: - ListenerExpectingErrors() - : has_error_(false) { - } + ListenerExpectingErrors() : has_error_(false) {} void OnChannelConnected(int32_t peer_pid) override { base::MessageLoop::current()->QuitWhenIdle(); @@ -221,30 +233,11 @@ class ListenerExpectingErrors : public IPC::Listener { bool has_error_; }; - -class IPCChannelMojoErrorTest : public IPCChannelMojoTestBase { - protected: - scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( - const IPC::ChannelHandle& handle, - base::SequencedTaskRunner* runner) override { - return IPC::ChannelMojo::CreateServerFactory(task_runner(), handle); - } - - bool DidStartClient() override { - bool ok = IPCTestBase::DidStartClient(); - DCHECK(ok); - return ok; - } -}; - class ListenerThatQuits : public IPC::Listener { public: - ListenerThatQuits() { - } + ListenerThatQuits() {} - bool OnMessageReceived(const IPC::Message& message) override { - return true; - } + bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnChannelConnected(int32_t peer_pid) override { base::MessageLoop::current()->QuitWhenIdle(); @@ -252,16 +245,14 @@ class ListenerThatQuits : public IPC::Listener { }; // A long running process that connects to us. -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) { +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoErraticTestClient, + ChannelClient) { ListenerThatQuits listener; - ChannelClient client(&listener, "IPCChannelMojoErraticTestClient"); - client.Connect(); + Connect(&listener); base::MessageLoop::current()->Run(); - client.Close(); - - return 0; + Close(); } // Times out on Android; see http://crbug.com/502290 @@ -270,7 +261,7 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) { #else #define MAYBE_SendFailWithPendingMessages SendFailWithPendingMessages #endif -TEST_F(IPCChannelMojoErrorTest, MAYBE_SendFailWithPendingMessages) { +TEST_F(IPCChannelMojoTest, MAYBE_SendFailWithPendingMessages) { InitWithMojo("IPCChannelMojoErraticTestClient"); // Set up IPC channel and start client. @@ -283,14 +274,13 @@ TEST_F(IPCChannelMojoErrorTest, MAYBE_SendFailWithPendingMessages) { std::string overly_large_data(kMaxMessageNumBytes, '*'); // This messages are queued as pending. for (size_t i = 0; i < 10; ++i) { - IPC::TestChannelListener::SendOneMessage( - sender(), overly_large_data.c_str()); + IPC::TestChannelListener::SendOneMessage(sender(), + overly_large_data.c_str()); } - ASSERT_TRUE(StartClient()); base::MessageLoop::current()->Run(); - this->channel()->Close(); + channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); EXPECT_TRUE(listener.has_error()); @@ -336,6 +326,9 @@ class HandleSendingHelper { std::string content(GetSendingFileContent().size(), ' '); uint32_t num_bytes = static_cast<uint32_t>(content.size()); + ASSERT_EQ(MOJO_RESULT_OK, + mojo::Wait(pipe.get(), MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, mojo::ReadMessageRaw(pipe.get(), &content[0], &num_bytes, nullptr, nullptr, 0)); @@ -378,9 +371,10 @@ class HandleSendingHelper { static void ReadReceivedFile(const IPC::Message& message, base::PickleIterator* iter) { base::ScopedFD fd; - scoped_refptr<IPC::MessageAttachment> attachment; + scoped_refptr<base::Pickle::Attachment> attachment; EXPECT_TRUE(message.ReadAttachment(iter, &attachment)); - base::File file(attachment->TakePlatformFile()); + base::File file(static_cast<IPC::MessageAttachment*>(attachment.get()) + ->TakePlatformFile()); std::string content(GetSendingFileContent().size(), ' '); file.Read(0, &content[0], content.size()); EXPECT_EQ(content, GetSendingFileContent()); @@ -422,34 +416,33 @@ TEST_F(IPCChannelMojoTest, MAYBE_SendMessagePipe) { ListenerThatExpectsOK listener; CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); TestingMessagePipe pipe; HandleSendingHelper::WritePipeThenSend(channel(), &pipe); base::MessageLoop::current()->Run(); - this->channel()->Close(); + channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendMessagePipeClient) { +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendMessagePipeClient, + ChannelClient) { ListenerThatExpectsMessagePipe listener; - ChannelClient client(&listener, "IPCChannelMojoTestSendMessagePipeClient"); - client.Connect(); - listener.set_sender(client.channel()); + Connect(&listener); + listener.set_sender(channel()); base::MessageLoop::current()->Run(); - client.Close(); - - return 0; + Close(); } void ReadOK(mojo::MessagePipeHandle pipe) { std::string should_be_ok("xx"); uint32_t num_bytes = static_cast<uint32_t>(should_be_ok.size()); + CHECK_EQ(MOJO_RESULT_OK, mojo::Wait(pipe, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, nullptr)); CHECK_EQ(MOJO_RESULT_OK, mojo::ReadMessageRaw(pipe, &should_be_ok[0], &num_bytes, nullptr, nullptr, 0)); @@ -494,18 +487,19 @@ class ListenerThatExpectsMessagePipeUsingParamTrait : public IPC::Listener { bool receiving_valid_; }; -void ParamTraitMessagePipeClient(bool receiving_valid_handle, - const char* channel_name) { - ListenerThatExpectsMessagePipeUsingParamTrait listener( - receiving_valid_handle); - ChannelClient client(&listener, channel_name); - client.Connect(); - listener.set_sender(client.channel()); +class ParamTraitMessagePipeClient : public ChannelClient { + public: + void RunTest(bool receiving_valid_handle) { + ListenerThatExpectsMessagePipeUsingParamTrait listener( + receiving_valid_handle); + Connect(&listener); + listener.set_sender(channel()); - base::MessageLoop::current()->Run(); + base::MessageLoop::current()->Run(); - client.Close(); -} + Close(); + } +}; // Times out on Android; see http://crbug.com/502290 #if defined(OS_ANDROID) @@ -519,7 +513,6 @@ TEST_F(IPCChannelMojoTest, MAYBE_ParamTraitValidMessagePipe) { ListenerThatExpectsOK listener; CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); TestingMessagePipe pipe; @@ -528,17 +521,17 @@ TEST_F(IPCChannelMojoTest, MAYBE_ParamTraitValidMessagePipe) { pipe.peer.release()); WriteOK(pipe.self.get()); - this->channel()->Send(message.release()); + channel()->Send(message.release()); base::MessageLoop::current()->Run(); - this->channel()->Close(); + channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ParamTraitValidMessagePipeClient) { - ParamTraitMessagePipeClient(true, "ParamTraitValidMessagePipeClient"); - return 0; +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(ParamTraitValidMessagePipeClient, + ParamTraitMessagePipeClient) { + RunTest(true); } // Times out on Android; see http://crbug.com/502290 @@ -553,37 +546,41 @@ TEST_F(IPCChannelMojoTest, MAYBE_ParamTraitInvalidMessagePipe) { ListenerThatExpectsOK listener; CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); mojo::MessagePipeHandle invalid_handle; scoped_ptr<IPC::Message> message(new IPC::Message()); IPC::ParamTraits<mojo::MessagePipeHandle>::Write(message.get(), invalid_handle); - this->channel()->Send(message.release()); + channel()->Send(message.release()); base::MessageLoop::current()->Run(); - this->channel()->Close(); + channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ParamTraitInvalidMessagePipeClient) { - ParamTraitMessagePipeClient(false, "ParamTraitInvalidMessagePipeClient"); - return 0; +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(ParamTraitInvalidMessagePipeClient, + ParamTraitMessagePipeClient) { + RunTest(false); } -TEST_F(IPCChannelMojoTest, SendFailAfterClose) { +// Times out on Android. crbug.com/593790 +#if defined(OS_ANDROID) +#define MAYBE_SendFailAfterClose DISABLED_SendFailAfterClose +#else +#define MAYBE_SendFailAfterClose SendFailAfterClose +#endif +TEST_F(IPCChannelMojoTest, MAYBE_SendFailAfterClose) { InitWithMojo("IPCChannelMojoTestSendOkClient"); ListenerThatExpectsOK listener; CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); base::MessageLoop::current()->Run(); - this->channel()->Close(); - ASSERT_FALSE(this->channel()->Send(new IPC::Message())); + channel()->Close(); + ASSERT_FALSE(channel()->Send(new IPC::Message())); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); @@ -591,12 +588,9 @@ TEST_F(IPCChannelMojoTest, SendFailAfterClose) { class ListenerSendingOneOk : public IPC::Listener { public: - ListenerSendingOneOk() { - } + ListenerSendingOneOk() {} - bool OnMessageReceived(const IPC::Message& message) override { - return true; - } + bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnChannelConnected(int32_t peer_pid) override { ListenerThatExpectsOK::SendOK(sender_); @@ -609,80 +603,21 @@ class ListenerSendingOneOk : public IPC::Listener { IPC::Sender* sender_; }; -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendOkClient) { +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendOkClient, + ChannelClient) { ListenerSendingOneOk listener; - ChannelClient client(&listener, "IPCChannelMojoTestSendOkClient"); - client.Connect(); - listener.set_sender(client.channel()); + Connect(&listener); + listener.set_sender(channel()); base::MessageLoop::current()->Run(); - client.Close(); - - return 0; + Close(); } -#if defined(OS_WIN) -class IPCChannelMojoDeadHandleTest : public IPCChannelMojoTestBase { - protected: - scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( - const IPC::ChannelHandle& handle, - base::SequencedTaskRunner* runner) override { - return IPC::ChannelMojo::CreateServerFactory(task_runner(), handle); - } - - bool DidStartClient() override { - IPCTestBase::DidStartClient(); - // const base::ProcessHandle client = client_process().Handle(); - // Forces GetFileHandleForProcess() fail. It happens occasionally - // in production, so we should exercise it somehow. - // TODO(morrita): figure out how to safely test this. See crbug.com/464109. - // ::CloseHandle(client); - return true; - } -}; - -TEST_F(IPCChannelMojoDeadHandleTest, InvalidClientHandle) { - // Any client type is fine as it is going to be killed anyway. - InitWithMojo("IPCChannelMojoTestDoNothingClient"); - - // Set up IPC channel and start client. - ListenerExpectingErrors listener; - CreateChannel(&listener); - ASSERT_TRUE(ConnectChannel()); - - ASSERT_TRUE(StartClient()); - base::MessageLoop::current()->Run(); - - this->channel()->Close(); - - // TODO(morrita): We need CloseHandle() call in DidStartClient(), - // which has been disabled since crrev.com/843113003, to - // make this fail. See crbug.com/464109. - // EXPECT_FALSE(WaitForClientShutdown()); - WaitForClientShutdown(); - EXPECT_TRUE(listener.has_error()); - - DestroyChannel(); -} - -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestDoNothingClient) { - ListenerThatQuits listener; - ChannelClient client(&listener, "IPCChannelMojoTestDoNothingClient"); - client.Connect(); - - // Quits without running the message loop as this client won't - // receive any messages from the server. - - return 0; -} -#endif - #if defined(OS_POSIX) class ListenerThatExpectsFile : public IPC::Listener { public: - ListenerThatExpectsFile() - : sender_(NULL) {} + ListenerThatExpectsFile() : sender_(NULL) {} ~ListenerThatExpectsFile() override {} @@ -694,9 +629,7 @@ class ListenerThatExpectsFile : public IPC::Listener { return true; } - void OnChannelError() override { - NOTREACHED(); - } + void OnChannelError() override { NOTREACHED(); } void set_sender(IPC::Sender* sender) { sender_ = sender; } @@ -716,7 +649,6 @@ TEST_F(IPCChannelMojoTest, MAYBE_SendPlatformHandle) { ListenerThatExpectsOK listener; CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); base::File file(HandleSendingHelper::GetSendingFilePath(), base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | @@ -724,24 +656,21 @@ TEST_F(IPCChannelMojoTest, MAYBE_SendPlatformHandle) { HandleSendingHelper::WriteFileThenSend(channel(), file); base::MessageLoop::current()->Run(); - this->channel()->Close(); + channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) { +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendPlatformHandleClient, + ChannelClient) { ListenerThatExpectsFile listener; - ChannelClient client( - &listener, "IPCChannelMojoTestSendPlatformHandleClient"); - client.Connect(); - listener.set_sender(client.channel()); + Connect(&listener); + listener.set_sender(channel()); base::MessageLoop::current()->Run(); - client.Close(); - - return 0; + Close(); } class ListenerThatExpectsFileAndPipe : public IPC::Listener { @@ -779,7 +708,6 @@ TEST_F(IPCChannelMojoTest, MAYBE_SendPlatformHandleAndPipe) { ListenerThatExpectsOK listener; CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); base::File file(HandleSendingHelper::GetSendingFilePath(), base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | @@ -788,25 +716,22 @@ TEST_F(IPCChannelMojoTest, MAYBE_SendPlatformHandleAndPipe) { HandleSendingHelper::WriteFileAndPipeThenSend(channel(), file, &pipe); base::MessageLoop::current()->Run(); - this->channel()->Close(); + channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } -MULTIPROCESS_IPC_TEST_CLIENT_MAIN( - IPCChannelMojoTestSendPlatformHandleAndPipeClient) { +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT( + IPCChannelMojoTestSendPlatformHandleAndPipeClient, + ChannelClient) { ListenerThatExpectsFileAndPipe listener; - ChannelClient client(&listener, - "IPCChannelMojoTestSendPlatformHandleAndPipeClient"); - client.Connect(); - listener.set_sender(client.channel()); + Connect(&listener); + listener.set_sender(channel()); base::MessageLoop::current()->Run(); - client.Close(); - - return 0; + Close(); } #endif @@ -834,7 +759,6 @@ TEST_F(IPCChannelMojoTest, VerifyGlobalPid) { ListenerThatVerifiesPeerPid listener; CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); base::MessageLoop::current()->Run(); channel()->Close(); @@ -843,20 +767,17 @@ TEST_F(IPCChannelMojoTest, VerifyGlobalPid) { DestroyChannel(); } -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestVerifyGlobalPidClient) { +DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestVerifyGlobalPidClient, + ChannelClient) { IPC::Channel::SetGlobalPid(kMagicChildId); ListenerThatQuits listener; - ChannelClient client(&listener, - "IPCChannelMojoTestVerifyGlobalPidClient"); - client.Connect(); + Connect(&listener); base::MessageLoop::current()->Run(); - client.Close(); - - return 0; + Close(); } -#endif // OS_LINUX +#endif // OS_LINUX } // namespace diff --git a/chromium/ipc/mojo/ipc_message_pipe_reader.cc b/chromium/ipc/mojo/ipc_message_pipe_reader.cc index 19d9e303a6d..b657bfdc168 100644 --- a/chromium/ipc/mojo/ipc_message_pipe_reader.cc +++ b/chromium/ipc/mojo/ipc_message_pipe_reader.cc @@ -5,66 +5,82 @@ #include "ipc/mojo/ipc_message_pipe_reader.h" #include <stdint.h> + #include <utility> #include "base/bind.h" #include "base/bind_helpers.h" #include "base/location.h" #include "base/logging.h" +#include "base/macros.h" #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" -#include "ipc/mojo/async_handle_waiter.h" #include "ipc/mojo/ipc_channel_mojo.h" +#include "mojo/public/cpp/bindings/message.h" namespace IPC { namespace internal { -MessagePipeReader::MessagePipeReader(mojo::ScopedMessagePipeHandle handle, - MessagePipeReader::Delegate* delegate) - : pipe_(std::move(handle)), - handle_copy_(pipe_.get().value()), - delegate_(delegate), - async_waiter_(new AsyncHandleWaiter( - base::Bind(&MessagePipeReader::PipeIsReady, base::Unretained(this)))), - pending_send_error_(MOJO_RESULT_OK) {} +namespace { -MessagePipeReader::~MessagePipeReader() { - DCHECK(thread_checker_.CalledOnValidThread()); - // The pipe should be closed before deletion. - CHECK(!IsValid()); -} +// Used by Send() to capture a serialized Channel::Receive message. +class MessageSerializer : public mojo::MessageReceiverWithResponder { + public: + MessageSerializer() {} + ~MessageSerializer() override {} -void MessagePipeReader::Close() { - DCHECK(thread_checker_.CalledOnValidThread()); - async_waiter_.reset(); - pipe_.reset(); - OnPipeClosed(); -} + mojo::Message* message() { return &message_; } -void MessagePipeReader::CloseWithError(MojoResult error) { - DCHECK(thread_checker_.CalledOnValidThread()); - OnPipeError(error); - Close(); + private: + // mojo::MessageReceiverWithResponder + bool Accept(mojo::Message* message) override { + message->MoveTo(&message_); + return true; + } + + bool AcceptWithResponder(mojo::Message* message, + mojo::MessageReceiver* responder) override { + NOTREACHED(); + return false; + } + + mojo::Message message_; + + DISALLOW_COPY_AND_ASSIGN(MessageSerializer); +}; + +} // namespace + +MessagePipeReader::MessagePipeReader( + mojo::MessagePipeHandle pipe, + mojom::ChannelAssociatedPtr sender, + mojo::AssociatedInterfaceRequest<mojom::Channel> receiver, + base::ProcessId peer_pid, + MessagePipeReader::Delegate* delegate) + : delegate_(delegate), + peer_pid_(peer_pid), + sender_(std::move(sender)), + binding_(this, std::move(receiver)), + sender_interface_id_(sender_.interface_id()), + sender_pipe_(pipe) { + sender_.set_connection_error_handler( + base::Bind(&MessagePipeReader::OnPipeError, base::Unretained(this), + MOJO_RESULT_FAILED_PRECONDITION)); + binding_.set_connection_error_handler( + base::Bind(&MessagePipeReader::OnPipeError, base::Unretained(this), + MOJO_RESULT_FAILED_PRECONDITION)); } -void MessagePipeReader::CloseWithErrorIfPending() { +MessagePipeReader::~MessagePipeReader() { DCHECK(thread_checker_.CalledOnValidThread()); - MojoResult pending_error = base::subtle::NoBarrier_Load(&pending_send_error_); - if (pending_error == MOJO_RESULT_OK) - return; - // NOTE: This races with Send(), and therefore the value of - // pending_send_error() can change. - CloseWithError(pending_error); - return; + // The pipe should be closed before deletion. } -void MessagePipeReader::CloseWithErrorLater(MojoResult error) { - DCHECK_NE(error, MOJO_RESULT_OK); - // NOTE: No assumptions about the value of |pending_send_error_| or whether or - // not the error has been signaled can be made. If Send() is called - // immediately before Close() and errors, it's possible for the error to not - // be signaled. - base::subtle::NoBarrier_Store(&pending_send_error_, error); +void MessagePipeReader::Close() { + DCHECK(thread_checker_.CalledOnValidThread()); + sender_.reset(); + if (binding_.is_bound()) + binding_.Close(); } bool MessagePipeReader::Send(scoped_ptr<Message> message) { @@ -72,165 +88,68 @@ bool MessagePipeReader::Send(scoped_ptr<Message> message) { "MessagePipeReader::Send", message->flags(), TRACE_EVENT_FLAG_FLOW_OUT); - std::vector<MojoHandle> handles; + mojo::Array<mojom::SerializedHandlePtr> handles(nullptr); MojoResult result = MOJO_RESULT_OK; result = ChannelMojo::ReadFromMessageAttachmentSet(message.get(), &handles); - if (result == MOJO_RESULT_OK) { - result = MojoWriteMessage(handle(), - message->data(), - static_cast<uint32_t>(message->size()), - handles.empty() ? nullptr : &handles[0], - static_cast<uint32_t>(handles.size()), - MOJO_WRITE_MESSAGE_FLAG_NONE); - } - - if (result != MOJO_RESULT_OK) { - std::for_each(handles.begin(), handles.end(), &MojoClose); - // We cannot call CloseWithError() here as Send() is protected by - // ChannelMojo's lock and CloseWithError() could re-enter ChannelMojo. We - // cannot call CloseWithError() also because Send() can be called from - // non-UI thread while OnPipeError() expects to be called on IO thread. - CloseWithErrorLater(result); + if (result != MOJO_RESULT_OK) return false; - } - return true; + mojo::Array<uint8_t> data(message->size()); + std::copy(reinterpret_cast<const uint8_t*>(message->data()), + reinterpret_cast<const uint8_t*>(message->data()) + message->size(), + &data[0]); + + MessageSerializer serializer; + mojom::ChannelProxy proxy(&serializer); + proxy.Receive(std::move(data), std::move(handles)); + mojo::Message* mojo_message = serializer.message(); + + size_t num_handles = mojo_message->handles()->size(); + DCHECK_LE(num_handles, std::numeric_limits<uint32_t>::max()); + + mojo_message->set_interface_id(sender_interface_id_); + result = mojo::WriteMessageRaw( + sender_pipe_, mojo_message->data(), mojo_message->data_num_bytes(), + reinterpret_cast<const MojoHandle*>(mojo_message->handles()->data()), + static_cast<uint32_t>(num_handles), MOJO_WRITE_MESSAGE_FLAG_NONE); + + // If the write was successful, the handles have been transferred and they + // should not be closed when the message is destroyed. + if (result == MOJO_RESULT_OK) + mojo_message->mutable_handles()->clear(); + + DVLOG(4) << "Send " << message->type() << ": " << message->size(); + return result == MOJO_RESULT_OK; } -void MessagePipeReader::OnMessageReceived() { - Message message(data_buffer().empty() ? "" : &data_buffer()[0], - static_cast<uint32_t>(data_buffer().size())); +void MessagePipeReader::Receive( + mojo::Array<uint8_t> data, + mojo::Array<mojom::SerializedHandlePtr> handles) { + Message message( + data.size() == 0 ? "" : reinterpret_cast<const char*>(&data[0]), + static_cast<uint32_t>(data.size())); + message.set_sender_pid(peer_pid_); - std::vector<MojoHandle> handle_buffer; - TakeHandleBuffer(&handle_buffer); + DVLOG(4) << "Receive " << message.type() << ": " << message.size(); MojoResult write_result = - ChannelMojo::WriteToMessageAttachmentSet(handle_buffer, &message); + ChannelMojo::WriteToMessageAttachmentSet(std::move(handles), &message); if (write_result != MOJO_RESULT_OK) { - CloseWithError(write_result); + OnPipeError(write_result); return; } TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), - "MessagePipeReader::OnMessageReceived", + "MessagePipeReader::Receive", message.flags(), TRACE_EVENT_FLAG_FLOW_IN); delegate_->OnMessageReceived(message); } -void MessagePipeReader::OnPipeClosed() { - DCHECK(thread_checker_.CalledOnValidThread()); - if (!delegate_) - return; - delegate_->OnPipeClosed(this); - delegate_ = nullptr; -} - void MessagePipeReader::OnPipeError(MojoResult error) { DCHECK(thread_checker_.CalledOnValidThread()); - if (!delegate_) - return; - delegate_->OnPipeError(this); -} - -MojoResult MessagePipeReader::ReadMessageBytes() { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(handle_buffer_.empty()); - - uint32_t num_bytes = static_cast<uint32_t>(data_buffer_.size()); - uint32_t num_handles = 0; - MojoResult result = MojoReadMessage(pipe_.get().value(), - num_bytes ? &data_buffer_[0] : nullptr, - &num_bytes, - nullptr, - &num_handles, - MOJO_READ_MESSAGE_FLAG_NONE); - data_buffer_.resize(num_bytes); - handle_buffer_.resize(num_handles); - if (result == MOJO_RESULT_RESOURCE_EXHAUSTED) { - // MOJO_RESULT_RESOURCE_EXHAUSTED was asking the caller that - // it needs more bufer. So we re-read it with resized buffers. - result = MojoReadMessage(pipe_.get().value(), - num_bytes ? &data_buffer_[0] : nullptr, - &num_bytes, - num_handles ? &handle_buffer_[0] : nullptr, - &num_handles, - MOJO_READ_MESSAGE_FLAG_NONE); - } - - DCHECK(0 == num_bytes || data_buffer_.size() == num_bytes); - DCHECK(0 == num_handles || handle_buffer_.size() == num_handles); - return result; -} - -void MessagePipeReader::ReadAvailableMessages() { - DCHECK(thread_checker_.CalledOnValidThread()); - while (pipe_.is_valid()) { - MojoResult read_result = ReadMessageBytes(); - if (read_result == MOJO_RESULT_SHOULD_WAIT) - break; - if (read_result != MOJO_RESULT_OK) { - DLOG(WARNING) - << "Pipe got error from ReadMessage(). Closing: " << read_result; - OnPipeError(read_result); - Close(); - break; - } - - OnMessageReceived(); - } - -} - -void MessagePipeReader::ReadMessagesThenWait() { - DCHECK(thread_checker_.CalledOnValidThread()); - while (true) { - ReadAvailableMessages(); - if (!pipe_.is_valid()) - break; - // |Wait()| is safe to call only after all messages are read. - // If can fail with |MOJO_RESULT_ALREADY_EXISTS| otherwise. - // Also, we don't use MOJO_HANDLE_SIGNAL_WRITABLE here, expecting buffer in - // MessagePipe. - MojoResult result = - async_waiter_->Wait(pipe_.get().value(), MOJO_HANDLE_SIGNAL_READABLE); - // If the result is |MOJO_RESULT_ALREADY_EXISTS|, there could be messages - // that have been arrived after the last |ReadAvailableMessages()|. - // We have to consume then and retry in that case. - if (result != MOJO_RESULT_ALREADY_EXISTS) { - if (result != MOJO_RESULT_OK) { - LOG(ERROR) << "Failed to wait on the pipe. Result is " << result; - OnPipeError(result); - Close(); - } - - break; - } - } -} - -void MessagePipeReader::PipeIsReady(MojoResult wait_result) { - DCHECK(thread_checker_.CalledOnValidThread()); - CloseWithErrorIfPending(); - if (!IsValid()) { - // There was a pending error and it closed the pipe. - // We cannot do the work anymore. - return; - } - - if (wait_result != MOJO_RESULT_OK) { - if (wait_result != MOJO_RESULT_ABORTED) { - // FAILED_PRECONDITION happens every time the peer is dead so - // it isn't worth polluting the log message. - LOG_IF(WARNING, wait_result != MOJO_RESULT_FAILED_PRECONDITION) - << "Pipe got error from the waiter. Closing: " << wait_result; - OnPipeError(wait_result); - } - - Close(); - return; - } - - ReadMessagesThenWait(); + if (delegate_) + delegate_->OnPipeError(); + Close(); } void MessagePipeReader::DelayedDeleter::operator()( diff --git a/chromium/ipc/mojo/ipc_message_pipe_reader.h b/chromium/ipc/mojo/ipc_message_pipe_reader.h index 375812305ca..d2ba9dea45d 100644 --- a/chromium/ipc/mojo/ipc_message_pipe_reader.h +++ b/chromium/ipc/mojo/ipc_message_pipe_reader.h @@ -16,8 +16,10 @@ #include "base/memory/scoped_ptr.h" #include "base/threading/thread_checker.h" #include "ipc/ipc_message.h" -#include "mojo/public/c/environment/async_waiter.h" +#include "ipc/mojo/ipc.mojom.h" +#include "mojo/public/cpp/bindings/associated_binding.h" #include "mojo/public/cpp/system/core.h" +#include "mojo/public/cpp/system/message_pipe.h" namespace IPC { namespace internal { @@ -40,13 +42,12 @@ class AsyncHandleWaiter; // be called on any thread. All |Delegate| functions will be called on the IO // thread. // -class MessagePipeReader { +class MessagePipeReader : public mojom::Channel { public: class Delegate { public: - virtual void OnMessageReceived(Message& message) = 0; - virtual void OnPipeClosed(MessagePipeReader* reader) = 0; - virtual void OnPipeError(MessagePipeReader* reader) = 0; + virtual void OnMessageReceived(const Message& message) = 0; + virtual void OnPipeError() = 0; }; // Delay the object deletion using the current message loop. @@ -64,61 +65,55 @@ class MessagePipeReader { void operator()(MessagePipeReader* ptr) const; }; - // Both parameters must be non-null. - // Build a reader that reads messages from |handle| and lets |delegate| know. - // Note that MessagePipeReader doesn't delete |delete|. - MessagePipeReader(mojo::ScopedMessagePipeHandle handle, Delegate* delegate); - virtual ~MessagePipeReader(); - - MojoHandle handle() const { return handle_copy_; } - - // Returns received bytes. - const std::vector<char>& data_buffer() const { - return data_buffer_; - } - - // Delegate received handles ownership. The subclass should take the - // ownership over in its OnMessageReceived(). They will leak otherwise. - void TakeHandleBuffer(std::vector<MojoHandle>* handle_buffer) { - handle_buffer_.swap(*handle_buffer); - } + // Builds a reader that reads messages from |receive_handle| and lets + // |delegate| know. + // + // |pipe| is the message pipe handle corresponding to the channel's master + // interface. This is the message pipe underlying both |sender| and + // |receiver|. + // + // Both |sender| and |receiver| must be non-null. + // + // Note that MessagePipeReader doesn't delete |delegate|. + MessagePipeReader(mojo::MessagePipeHandle pipe, + mojom::ChannelAssociatedPtr sender, + mojo::AssociatedInterfaceRequest<mojom::Channel> receiver, + base::ProcessId peer_pid, + Delegate* delegate); + ~MessagePipeReader() override; // Close and destroy the MessagePipe. void Close(); - // Close the mesage pipe with notifying the client with the error. - void CloseWithError(MojoResult error); - void CloseWithErrorLater(MojoResult error); - void CloseWithErrorIfPending(); // Return true if the MessagePipe is alive. - bool IsValid() { return pipe_.is_valid(); } + bool IsValid() { return sender_; } + // Sends an IPC::Message to the other end of the pipe. Safe to call from any + // thread. bool Send(scoped_ptr<Message> message); - void ReadMessagesThenWait(); - private: - void OnMessageReceived(); + base::ProcessId GetPeerPid() const { return peer_pid_; } + + protected: void OnPipeClosed(); void OnPipeError(MojoResult error); - MojoResult ReadMessageBytes(); - void PipeIsReady(MojoResult wait_result); - void ReadAvailableMessages(); - - std::vector<char> data_buffer_; - std::vector<MojoHandle> handle_buffer_; - mojo::ScopedMessagePipeHandle pipe_; - // Constant copy of the message pipe handle. For use by Send(), which can run - // concurrently on non-IO threads. - // TODO(amistry): This isn't quite right because handles can be re-used and - // using this can run into the ABA problem. Currently, this is highly unlikely - // because Mojo internally uses an increasing uint32_t as handle values, but - // this could change. See crbug.com/524894. - const MojoHandle handle_copy_; - // |delegate_| and |async_waiter_| are null once the message pipe is closed. + private: + // mojom::Channel: + void Receive(mojo::Array<uint8_t> data, + mojo::Array<mojom::SerializedHandlePtr> handles) override; + + // |delegate_| is null once the message pipe is closed. Delegate* delegate_; - scoped_ptr<AsyncHandleWaiter> async_waiter_; - base::subtle::Atomic32 pending_send_error_; + base::ProcessId peer_pid_; + mojom::ChannelAssociatedPtr sender_; + mojo::AssociatedBinding<mojom::Channel> binding_; + + // Raw message pipe handle and interface ID we use to send legacy IPC messages + // over the associated pipe. + const uint32_t sender_interface_id_; + const mojo::MessagePipeHandle sender_pipe_; + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(MessagePipeReader); diff --git a/chromium/ipc/mojo/ipc_mojo.gyp b/chromium/ipc/mojo/ipc_mojo.gyp index 313ecb2c99c..75c85d9824a 100644 --- a/chromium/ipc/mojo/ipc_mojo.gyp +++ b/chromium/ipc/mojo/ipc_mojo.gyp @@ -17,19 +17,15 @@ 'defines': [ 'IPC_MOJO_IMPLEMENTATION', ], - 'includes': [ '../../third_party/mojo/mojom_bindings_generator.gypi' ], + 'includes': [ '../../mojo/mojom_bindings_generator.gypi' ], 'dependencies': [ '../ipc.gyp:ipc', '../../base/base.gyp:base', '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - '../../mojo/mojo_base.gyp:mojo_environment_chromium', - '../../third_party/mojo/mojo_edk.gyp:mojo_system_impl', - '../../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', + '../../mojo/mojo_edk.gyp:mojo_system_impl', + '../../mojo/mojo_public.gyp:mojo_cpp_bindings', ], 'sources': [ - 'client_channel.mojom', - 'async_handle_waiter.cc', - 'async_handle_waiter.h', 'ipc_channel_mojo.cc', 'ipc_channel_mojo.h', 'ipc_mojo_bootstrap.cc', @@ -42,6 +38,7 @@ 'ipc_mojo_param_traits.h', 'ipc_message_pipe_reader.cc', 'ipc_message_pipe_reader.h', + 'ipc.mojom', 'scoped_ipc_support.cc', 'scoped_ipc_support.h', ], @@ -62,19 +59,19 @@ '../../base/base.gyp:base', '../../base/base.gyp:base_i18n', '../../base/base.gyp:test_support_base', - '../../mojo/mojo_base.gyp:mojo_environment_chromium', + '../../mojo/mojo_edk.gyp:mojo_common_test_support', + '../../mojo/mojo_edk.gyp:mojo_system_impl', + '../../mojo/mojo_public.gyp:mojo_cpp_bindings', '../../testing/gtest.gyp:gtest', - '../../third_party/mojo/mojo_edk.gyp:mojo_system_impl', - '../../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', 'ipc_mojo', ], 'include_dirs': [ '..' ], 'sources': [ - 'async_handle_waiter_unittest.cc', 'run_all_unittests.cc', - 'ipc_channel_mojo_unittest.cc', + + "ipc_channel_mojo_unittest.cc", 'ipc_mojo_bootstrap_unittest.cc', ], 'conditions': [ @@ -90,10 +87,10 @@ '../../base/base.gyp:base_i18n', '../../base/base.gyp:test_support_base', '../../base/base.gyp:test_support_perf', - '../../mojo/mojo_base.gyp:mojo_environment_chromium', + '../../mojo/mojo_edk.gyp:mojo_common_test_support', + '../../mojo/mojo_edk.gyp:mojo_system_impl', + '../../mojo/mojo_public.gyp:mojo_cpp_bindings', '../../testing/gtest.gyp:gtest', - '../../third_party/mojo/mojo_edk.gyp:mojo_system_impl', - '../../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', 'ipc_mojo', ], 'include_dirs': [ diff --git a/chromium/ipc/mojo/ipc_mojo_bootstrap.cc b/chromium/ipc/mojo/ipc_mojo_bootstrap.cc index d2966756605..a80b4610301 100644 --- a/chromium/ipc/mojo/ipc_mojo_bootstrap.cc +++ b/chromium/ipc/mojo/ipc_mojo_bootstrap.cc @@ -13,7 +13,9 @@ #include "build/build_config.h" #include "ipc/ipc_message_utils.h" #include "ipc/ipc_platform_file.h" -#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/public/cpp/bindings/binding.h" namespace IPC { @@ -26,127 +28,96 @@ class MojoServerBootstrap : public MojoBootstrap { MojoServerBootstrap(); private: - void SendClientPipe(int32_t peer_pid); + // MojoBootstrap implementation. + void Connect() override; - // Listener implementations - bool OnMessageReceived(const Message& message) override; - void OnChannelConnected(int32_t peer_pid) override; + void OnInitDone(int32_t peer_pid); - mojo::embedder::ScopedPlatformHandle server_pipe_; - bool connected_; - int32_t peer_pid_; + mojom::BootstrapPtr bootstrap_; + IPC::mojom::ChannelAssociatedPtrInfo send_channel_; + IPC::mojom::ChannelAssociatedRequest receive_channel_request_; DISALLOW_COPY_AND_ASSIGN(MojoServerBootstrap); }; -MojoServerBootstrap::MojoServerBootstrap() : connected_(false), peer_pid_(0) { -} +MojoServerBootstrap::MojoServerBootstrap() = default; -void MojoServerBootstrap::SendClientPipe(int32_t peer_pid) { +void MojoServerBootstrap::Connect() { DCHECK_EQ(state(), STATE_INITIALIZED); - DCHECK(connected_); - - mojo::embedder::PlatformChannelPair channel_pair; - server_pipe_ = channel_pair.PassServerHandle(); - - base::Process peer_process = -#if defined(OS_WIN) - base::Process::OpenWithAccess(peer_pid, PROCESS_DUP_HANDLE); -#else - base::Process::Open(peer_pid); -#endif - PlatformFileForTransit client_pipe = GetFileHandleForProcess( -#if defined(OS_POSIX) - channel_pair.PassClientHandle().release().fd, -#else - channel_pair.PassClientHandle().release().handle, -#endif - peer_process.Handle(), true); - if (client_pipe == IPC::InvalidPlatformFileForTransit()) { -#if !defined(OS_WIN) - // GetFileHandleForProcess() only fails on Windows. - NOTREACHED(); -#endif - LOG(WARNING) << "Failed to translate file handle for client process."; - Fail(); - return; - } - scoped_ptr<Message> message(new Message()); - ParamTraits<PlatformFileForTransit>::Write(message.get(), client_pipe); - Send(message.release()); + bootstrap_.Bind(mojom::BootstrapPtrInfo(TakeHandle(), 0)); + bootstrap_.set_connection_error_handler( + base::Bind(&MojoServerBootstrap::Fail, base::Unretained(this))); - set_state(STATE_WAITING_ACK); -} + IPC::mojom::ChannelAssociatedRequest send_channel_request; + IPC::mojom::ChannelAssociatedPtrInfo receive_channel; -void MojoServerBootstrap::OnChannelConnected(int32_t peer_pid) { - DCHECK_EQ(state(), STATE_INITIALIZED); - connected_ = true; - peer_pid_ = peer_pid; - SendClientPipe(peer_pid); + bootstrap_.associated_group()->CreateAssociatedInterface( + mojo::AssociatedGroup::WILL_PASS_REQUEST, &send_channel_, + &send_channel_request); + bootstrap_.associated_group()->CreateAssociatedInterface( + mojo::AssociatedGroup::WILL_PASS_PTR, &receive_channel, + &receive_channel_request_); + + bootstrap_->Init( + std::move(send_channel_request), std::move(receive_channel), + GetSelfPID(), + base::Bind(&MojoServerBootstrap::OnInitDone, base::Unretained(this))); + + set_state(STATE_WAITING_ACK); } -bool MojoServerBootstrap::OnMessageReceived(const Message&) { +void MojoServerBootstrap::OnInitDone(int32_t peer_pid) { if (state() != STATE_WAITING_ACK) { set_state(STATE_ERROR); LOG(ERROR) << "Got inconsistent message from client."; - return false; + return; } set_state(STATE_READY); - CHECK(server_pipe_.is_valid()); - delegate()->OnPipeAvailable( - mojo::embedder::ScopedPlatformHandle(server_pipe_.release()), peer_pid_); - - return true; + bootstrap_.set_connection_error_handler(mojo::Closure()); + delegate()->OnPipesAvailable(std::move(send_channel_), + std::move(receive_channel_request_), peer_pid); } // MojoBootstrap for client processes. You should create the instance // using MojoBootstrap::Create(). -class MojoClientBootstrap : public MojoBootstrap { +class MojoClientBootstrap : public MojoBootstrap, public mojom::Bootstrap { public: MojoClientBootstrap(); private: - // Listener implementations - bool OnMessageReceived(const Message& message) override; - void OnChannelConnected(int32_t peer_pid) override; + // MojoBootstrap implementation. + void Connect() override; - int32_t peer_pid_; + // mojom::Bootstrap implementation. + void Init(mojom::ChannelAssociatedRequest receive_channel, + mojom::ChannelAssociatedPtrInfo send_channel, + int32_t peer_pid, + const mojo::Callback<void(int32_t)>& callback) override; + + mojo::Binding<mojom::Bootstrap> binding_; DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap); }; -MojoClientBootstrap::MojoClientBootstrap() : peer_pid_(0) { -} - -bool MojoClientBootstrap::OnMessageReceived(const Message& message) { - if (state() != STATE_INITIALIZED) { - set_state(STATE_ERROR); - LOG(ERROR) << "Got inconsistent message from server."; - return false; - } +MojoClientBootstrap::MojoClientBootstrap() : binding_(this) {} - PlatformFileForTransit pipe; - base::PickleIterator iter(message); - if (!ParamTraits<PlatformFileForTransit>::Read(&message, &iter, &pipe)) { - LOG(WARNING) << "Failed to read a file handle from bootstrap channel."; - message.set_dispatch_error(); - return false; - } - - // Sends ACK back. - Send(new Message()); - set_state(STATE_READY); - delegate()->OnPipeAvailable( - mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle( - PlatformFileForTransitToPlatformFile(pipe))), peer_pid_); - - return true; +void MojoClientBootstrap::Connect() { + binding_.Bind(TakeHandle()); + binding_.set_connection_error_handler( + base::Bind(&MojoClientBootstrap::Fail, base::Unretained(this))); } -void MojoClientBootstrap::OnChannelConnected(int32_t peer_pid) { - peer_pid_ = peer_pid; +void MojoClientBootstrap::Init(mojom::ChannelAssociatedRequest receive_channel, + mojom::ChannelAssociatedPtrInfo send_channel, + int32_t peer_pid, + const mojo::Callback<void(int32_t)>& callback) { + callback.Run(GetSelfPID()); + set_state(STATE_READY); + binding_.set_connection_error_handler(mojo::Closure()); + delegate()->OnPipesAvailable(std::move(send_channel), + std::move(receive_channel), peer_pid); } } // namespace @@ -154,49 +125,37 @@ void MojoClientBootstrap::OnChannelConnected(int32_t peer_pid) { // MojoBootstrap // static -scoped_ptr<MojoBootstrap> MojoBootstrap::Create(ChannelHandle handle, - Channel::Mode mode, - Delegate* delegate) { +scoped_ptr<MojoBootstrap> MojoBootstrap::Create( + mojo::ScopedMessagePipeHandle handle, + Channel::Mode mode, + Delegate* delegate) { CHECK(mode == Channel::MODE_CLIENT || mode == Channel::MODE_SERVER); scoped_ptr<MojoBootstrap> self = mode == Channel::MODE_CLIENT ? scoped_ptr<MojoBootstrap>(new MojoClientBootstrap()) : scoped_ptr<MojoBootstrap>(new MojoServerBootstrap()); - scoped_ptr<Channel> bootstrap_channel = - Channel::Create(handle, mode, self.get()); - self->Init(std::move(bootstrap_channel), delegate); + self->Init(std::move(handle), delegate); return self; } MojoBootstrap::MojoBootstrap() : delegate_(NULL), state_(STATE_INITIALIZED) { } -MojoBootstrap::~MojoBootstrap() { -} +MojoBootstrap::~MojoBootstrap() {} -void MojoBootstrap::Init(scoped_ptr<Channel> channel, Delegate* delegate) { - channel_ = std::move(channel); +void MojoBootstrap::Init(mojo::ScopedMessagePipeHandle handle, + Delegate* delegate) { + handle_ = std::move(handle); delegate_ = delegate; } -bool MojoBootstrap::Connect() { - return channel_->Connect(); -} - base::ProcessId MojoBootstrap::GetSelfPID() const { - return channel_->GetSelfPID(); -} - -void MojoBootstrap::OnBadMessageReceived(const Message& message) { - Fail(); -} - -void MojoBootstrap::OnChannelError() { - if (state_ == STATE_READY || state_ == STATE_ERROR) - return; - DLOG(WARNING) << "Detected error on Mojo bootstrap channel."; - Fail(); +#if defined(OS_LINUX) + if (int global_pid = Channel::GetGlobalPid()) + return global_pid; +#endif // OS_LINUX + return base::GetCurrentProcId(); } void MojoBootstrap::Fail() { @@ -208,18 +167,8 @@ bool MojoBootstrap::HasFailed() const { return state() == STATE_ERROR; } -bool MojoBootstrap::Send(Message* message) { - return channel_->Send(message); -} - -#if defined(OS_POSIX) && !defined(OS_NACL) -int MojoBootstrap::GetClientFileDescriptor() const { - return channel_->GetClientFileDescriptor(); -} - -base::ScopedFD MojoBootstrap::TakeClientFileDescriptor() { - return channel_->TakeClientFileDescriptor(); +mojo::ScopedMessagePipeHandle MojoBootstrap::TakeHandle() { + return std::move(handle_); } -#endif // defined(OS_POSIX) && !defined(OS_NACL) } // namespace IPC diff --git a/chromium/ipc/mojo/ipc_mojo_bootstrap.h b/chromium/ipc/mojo/ipc_mojo_bootstrap.h index 4b5ccfb71e9..23e0e9193b7 100644 --- a/chromium/ipc/mojo/ipc_mojo_bootstrap.h +++ b/chromium/ipc/mojo/ipc_mojo_bootstrap.h @@ -13,50 +13,46 @@ #include "build/build_config.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_listener.h" -#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h" +#include "ipc/mojo/ipc.mojom.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/public/cpp/system/message_pipe.h" namespace IPC { -// MojoBootstrap establishes a bootstrap pipe between two processes in -// Chrome. It creates a native IPC::Channel first, then sends one -// side of a newly created pipe to peer process. The pipe is intended -// to be wrapped by Mojo MessagePipe. +// MojoBootstrap establishes a pair of associated interfaces between two +// processes in Chrome. // -// Clients should implement MojoBootstrapDelegate to get the pipe +// Clients should implement MojoBootstrap::Delegate to get the associated pipes // from MojoBootstrap object. // // This lives on IO thread other than Create(), which can be called from // UI thread as Channel::Create() can be. -class IPC_MOJO_EXPORT MojoBootstrap : public Listener { +class IPC_MOJO_EXPORT MojoBootstrap { public: class Delegate { public: - virtual void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle, - int32_t peer_pid) = 0; + virtual void OnPipesAvailable( + mojom::ChannelAssociatedPtrInfo send_channel, + mojom::ChannelAssociatedRequest receive_channel, + int32_t peer_pid) = 0; virtual void OnBootstrapError() = 0; }; - // Create the MojoBootstrap instance. - // Instead of creating IPC::Channel, passs its ChannelHandle as |handle|, - // mode as |mode|. The result is notified to passed |delegate|. - static scoped_ptr<MojoBootstrap> Create(ChannelHandle handle, + // Create the MojoBootstrap instance, using |handle| as the message pipe, in + // mode as specified by |mode|. The result is passed to |delegate|. + static scoped_ptr<MojoBootstrap> Create(mojo::ScopedMessagePipeHandle handle, Channel::Mode mode, Delegate* delegate); MojoBootstrap(); - ~MojoBootstrap() override; + virtual ~MojoBootstrap(); - // Start the handshake over the underlying platform channel. - bool Connect(); + // Start the handshake over the underlying message pipe. + virtual void Connect() = 0; - // GetSelfPID returns the PID associated with |channel_|. + // GetSelfPID returns our PID. base::ProcessId GetSelfPID() const; -#if defined(OS_POSIX) && !defined(OS_NACL) - int GetClientFileDescriptor() const; - base::ScopedFD TakeClientFileDescriptor(); -#endif // defined(OS_POSIX) && !defined(OS_NACL) - protected: // On MojoServerBootstrap: INITIALIZED -> WAITING_ACK -> READY // On MojoClientBootstrap: INITIALIZED -> READY @@ -64,21 +60,18 @@ class IPC_MOJO_EXPORT MojoBootstrap : public Listener { enum State { STATE_INITIALIZED, STATE_WAITING_ACK, STATE_READY, STATE_ERROR }; Delegate* delegate() const { return delegate_; } - bool Send(Message* message); void Fail(); bool HasFailed() const; State state() const { return state_; } void set_state(State state) { state_ = state; } - private: - void Init(scoped_ptr<Channel> channel, Delegate* delegate); + mojo::ScopedMessagePipeHandle TakeHandle(); - // Listener implementations - void OnBadMessageReceived(const Message& message) override; - void OnChannelError() override; + private: + void Init(mojo::ScopedMessagePipeHandle, Delegate* delegate); - scoped_ptr<Channel> channel_; + mojo::ScopedMessagePipeHandle handle_; Delegate* delegate_; State state_; diff --git a/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc b/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc index 60046d16c52..d702a6ae7b8 100644 --- a/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc +++ b/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc @@ -9,8 +9,14 @@ #include "base/base_paths.h" #include "base/files/file.h" #include "base/message_loop/message_loop.h" +#include "base/thread_task_runner_handle.h" #include "build/build_config.h" #include "ipc/ipc_test_base.h" +#include "ipc/mojo/ipc.mojom.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/test/mojo_test_base.h" +#include "mojo/edk/test/multiprocess_test_helper.h" +#include "mojo/edk/test/scoped_ipc_support.h" #if defined(OS_POSIX) #include "base/file_descriptor_posix.h" @@ -18,33 +24,38 @@ namespace { -class IPCMojoBootstrapTest : public IPCTestBase { +class IPCMojoBootstrapTest : public testing::Test { protected: + mojo::edk::test::MultiprocessTestHelper helper_; }; class TestingDelegate : public IPC::MojoBootstrap::Delegate { public: - TestingDelegate() : passed_(false) {} + explicit TestingDelegate(const base::Closure& quit_callback) + : passed_(false), quit_callback_(quit_callback) {} - void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle, - int32_t peer_pid) override; + void OnPipesAvailable(IPC::mojom::ChannelAssociatedPtrInfo send_channel, + IPC::mojom::ChannelAssociatedRequest receive_channel, + int32_t peer_pid) override; void OnBootstrapError() override; bool passed() const { return passed_; } private: bool passed_; + const base::Closure quit_callback_; }; -void TestingDelegate::OnPipeAvailable( - mojo::embedder::ScopedPlatformHandle handle, +void TestingDelegate::OnPipesAvailable( + IPC::mojom::ChannelAssociatedPtrInfo send_channel, + IPC::mojom::ChannelAssociatedRequest receive_channel, int32_t peer_pid) { passed_ = true; - base::MessageLoop::current()->QuitWhenIdle(); + quit_callback_.Run(); } void TestingDelegate::OnBootstrapError() { - base::MessageLoop::current()->QuitWhenIdle(); + quit_callback_.Run(); } // Times out on Android; see http://crbug.com/502290 @@ -54,41 +65,37 @@ void TestingDelegate::OnBootstrapError() { #define MAYBE_Connect Connect #endif TEST_F(IPCMojoBootstrapTest, MAYBE_Connect) { - Init("IPCMojoBootstrapTestClient"); - - TestingDelegate delegate; + base::MessageLoop message_loop; + base::RunLoop run_loop; + TestingDelegate delegate(run_loop.QuitClosure()); scoped_ptr<IPC::MojoBootstrap> bootstrap = IPC::MojoBootstrap::Create( - GetTestChannelHandle(), IPC::Channel::MODE_SERVER, &delegate); - - ASSERT_TRUE(bootstrap->Connect()); -#if defined(OS_POSIX) - ASSERT_TRUE(StartClientWithFD(bootstrap->GetClientFileDescriptor())); -#else - ASSERT_TRUE(StartClient()); -#endif + helper_.StartChild("IPCMojoBootstrapTestClient"), + IPC::Channel::MODE_SERVER, &delegate); - base::MessageLoop::current()->Run(); + bootstrap->Connect(); + run_loop.Run(); EXPECT_TRUE(delegate.passed()); - EXPECT_TRUE(WaitForClientShutdown()); + EXPECT_TRUE(helper_.WaitForChildTestShutdown()); } // A long running process that connects to us. -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCMojoBootstrapTestClient) { - base::MessageLoopForIO main_message_loop; - - TestingDelegate delegate; +MULTIPROCESS_TEST_MAIN_WITH_SETUP( + IPCMojoBootstrapTestClientTestChildMain, + ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) { + base::MessageLoop message_loop; + base::RunLoop run_loop; + TestingDelegate delegate(run_loop.QuitClosure()); scoped_ptr<IPC::MojoBootstrap> bootstrap = IPC::MojoBootstrap::Create( - IPCTestBase::GetChannelName("IPCMojoBootstrapTestClient"), + mojo::edk::CreateChildMessagePipe( + mojo::edk::test::MultiprocessTestHelper::primordial_pipe_token), IPC::Channel::MODE_CLIENT, &delegate); bootstrap->Connect(); - base::MessageLoop::current()->Run(); - - EXPECT_TRUE(delegate.passed()); + run_loop.Run(); - return 0; + return delegate.passed() ? 0 : 1; } } // namespace diff --git a/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc b/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc index 70b80c57b13..b2e16f121c5 100644 --- a/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc +++ b/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc @@ -8,7 +8,7 @@ #include "build/build_config.h" #include "ipc/ipc_message_attachment_set.h" -#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/embedder.h" namespace IPC { namespace internal { @@ -25,16 +25,15 @@ MessageAttachment::Type MojoHandleAttachment::GetType() const { #if defined(OS_POSIX) base::PlatformFile MojoHandleAttachment::TakePlatformFile() { - mojo::embedder::ScopedPlatformHandle platform_handle; - MojoResult unwrap_result = mojo::embedder::PassWrappedPlatformHandle( - handle_.get().value(), &platform_handle); - handle_.reset(); + mojo::edk::ScopedPlatformHandle platform_handle; + MojoResult unwrap_result = mojo::edk::PassWrappedPlatformHandle( + handle_.release().value(), &platform_handle); if (unwrap_result != MOJO_RESULT_OK) { LOG(ERROR) << "Pipe failed to covert handles. Closing: " << unwrap_result; return -1; } - return platform_handle.release().fd; + return platform_handle.release().handle; } #endif // OS_POSIX diff --git a/chromium/ipc/mojo/ipc_mojo_message_helper.cc b/chromium/ipc/mojo/ipc_mojo_message_helper.cc index 8b8344ec766..ae5e83a2cdb 100644 --- a/chromium/ipc/mojo/ipc_mojo_message_helper.cc +++ b/chromium/ipc/mojo/ipc_mojo_message_helper.cc @@ -12,7 +12,7 @@ namespace IPC { // static bool MojoMessageHelper::WriteMessagePipeTo( - Message* message, + base::Pickle* message, mojo::ScopedMessagePipeHandle handle) { message->WriteAttachment(new internal::MojoHandleAttachment( mojo::ScopedHandle::From(std::move(handle)))); @@ -21,17 +21,19 @@ bool MojoMessageHelper::WriteMessagePipeTo( // static bool MojoMessageHelper::ReadMessagePipeFrom( - const Message* message, + const base::Pickle* message, base::PickleIterator* iter, mojo::ScopedMessagePipeHandle* handle) { - scoped_refptr<MessageAttachment> attachment; + scoped_refptr<base::Pickle::Attachment> attachment; if (!message->ReadAttachment(iter, &attachment)) { LOG(ERROR) << "Failed to read attachment for message pipe."; return false; } - if (attachment->GetType() != MessageAttachment::TYPE_MOJO_HANDLE) { - LOG(ERROR) << "Unxpected attachment type:" << attachment->GetType(); + MessageAttachment::Type type = + static_cast<MessageAttachment*>(attachment.get())->GetType(); + if (type != MessageAttachment::TYPE_MOJO_HANDLE) { + LOG(ERROR) << "Unxpected attachment type:" << type; return false; } diff --git a/chromium/ipc/mojo/ipc_mojo_message_helper.h b/chromium/ipc/mojo/ipc_mojo_message_helper.h index 3dc840e92e3..e0e44d075d0 100644 --- a/chromium/ipc/mojo/ipc_mojo_message_helper.h +++ b/chromium/ipc/mojo/ipc_mojo_message_helper.h @@ -14,9 +14,9 @@ namespace IPC { // Reads and writes |mojo::MessagePipe| from/to |Message|. class IPC_MOJO_EXPORT MojoMessageHelper { public: - static bool WriteMessagePipeTo(Message* message, + static bool WriteMessagePipeTo(base::Pickle* message, mojo::ScopedMessagePipeHandle handle); - static bool ReadMessagePipeFrom(const Message* message, + static bool ReadMessagePipeFrom(const base::Pickle* message, base::PickleIterator* iter, mojo::ScopedMessagePipeHandle* handle); diff --git a/chromium/ipc/mojo/ipc_mojo_perftest.cc b/chromium/ipc/mojo/ipc_mojo_perftest.cc index d782c77ee59..b1c6c86b6c7 100644 --- a/chromium/ipc/mojo/ipc_mojo_perftest.cc +++ b/chromium/ipc/mojo/ipc_mojo_perftest.cc @@ -4,55 +4,45 @@ #include <stddef.h> -#include "base/lazy_instance.h" #include "base/run_loop.h" +#include "base/thread_task_runner_handle.h" #include "build/build_config.h" #include "ipc/ipc_perftest_support.h" #include "ipc/mojo/ipc_channel_mojo.h" -#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" -#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/test/multiprocess_test_helper.h" +#include "mojo/edk/test/scoped_ipc_support.h" +namespace IPC { namespace { -// This is needed because we rely on //base/test:test_support_perf and -// it provides main() which doesn't have Mojo initialization. We need -// some way to call Init() only once before using Mojo. -struct MojoInitialier { - MojoInitialier() { - mojo::embedder::Init(); - } -}; - -base::LazyInstance<MojoInitialier> g_mojo_initializer - = LAZY_INSTANCE_INITIALIZER; - -class MojoChannelPerfTest : public IPC::test::IPCChannelPerfTestBase { -public: - typedef IPC::test::IPCChannelPerfTestBase Super; - - MojoChannelPerfTest(); - +class MojoChannelPerfTest : public test::IPCChannelPerfTestBase { + public: void TearDown() override { - IPC::test::IPCChannelPerfTestBase::TearDown(); + ipc_support_.reset(); + test::IPCChannelPerfTestBase::TearDown(); } - scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( - const IPC::ChannelHandle& handle, + scoped_ptr<ChannelFactory> CreateChannelFactory( + const ChannelHandle& handle, base::SequencedTaskRunner* runner) override { - return IPC::ChannelMojo::CreateServerFactory(runner, handle); + ipc_support_.reset(new mojo::edk::test::ScopedIPCSupport(io_task_runner())); + return ChannelMojo::CreateServerFactory( + helper_.StartChild("MojoPerfTestClient")); } - bool DidStartClient() override { - bool ok = IPCTestBase::DidStartClient(); - DCHECK(ok); - return ok; + bool StartClient() override { + return true; } -}; -MojoChannelPerfTest::MojoChannelPerfTest() { - g_mojo_initializer.Get(); -} + bool WaitForClientShutdown() override { + return helper_.WaitForChildTestShutdown(); + } + mojo::edk::test::MultiprocessTestHelper helper_; + scoped_ptr<mojo::edk::test::ScopedIPCSupport> ipc_support_; +}; TEST_F(MojoChannelPerfTest, ChannelPingPong) { RunTestChannelPingPong(GetDefaultTestParams()); @@ -75,36 +65,47 @@ TEST_F(MojoChannelPerfTest, DISABLED_MaxChannelCount) { base::SetFdLimit(20000); #endif - std::vector<mojo::embedder::PlatformChannelPair*> channels; + std::vector<mojo::edk::PlatformChannelPair*> channels; for (size_t i = 0; i < 10000; ++i) { LOG(INFO) << "channels size: " << channels.size(); - channels.push_back(new mojo::embedder::PlatformChannelPair()); + channels.push_back(new mojo::edk::PlatformChannelPair()); } } -class MojoTestClient : public IPC::test::PingPongTestClient { +class MojoPerfTestClient : public test::PingPongTestClient { public: - typedef IPC::test::PingPongTestClient SuperType; + typedef test::PingPongTestClient SuperType; + + MojoPerfTestClient(); - MojoTestClient(); + scoped_ptr<Channel> CreateChannel(Listener* listener) override; - scoped_ptr<IPC::Channel> CreateChannel(IPC::Listener* listener) override; + int Run(MojoHandle handle); + + private: + mojo::edk::test::ScopedIPCSupport ipc_support_; + mojo::ScopedMessagePipeHandle handle_; }; -MojoTestClient::MojoTestClient() { - g_mojo_initializer.Get(); +MojoPerfTestClient::MojoPerfTestClient() + : ipc_support_(base::ThreadTaskRunnerHandle::Get()) { + mojo::edk::test::MultiprocessTestHelper::ChildSetup(); +} + +scoped_ptr<Channel> MojoPerfTestClient::CreateChannel(Listener* listener) { + return scoped_ptr<Channel>( + ChannelMojo::Create(std::move(handle_), Channel::MODE_CLIENT, listener)); } -scoped_ptr<IPC::Channel> MojoTestClient::CreateChannel( - IPC::Listener* listener) { - return scoped_ptr<IPC::Channel>(IPC::ChannelMojo::Create( - task_runner(), IPCTestBase::GetChannelName("PerformanceClient"), - IPC::Channel::MODE_CLIENT, listener)); +int MojoPerfTestClient::Run(MojoHandle handle) { + handle_ = mojo::MakeScopedHandle(mojo::MessagePipeHandle(handle)); + return RunMain(); } -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) { - MojoTestClient client; - int rv = client.RunMain(); +MULTIPROCESS_TEST_MAIN(MojoPerfTestClientTestChildMain) { + MojoPerfTestClient client; + int rv = mojo::edk::test::MultiprocessTestHelper::RunClientMain( + base::Bind(&MojoPerfTestClient::Run, base::Unretained(&client))); base::RunLoop run_loop; run_loop.RunUntilIdle(); @@ -113,3 +114,4 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) { } } // namespace +} // namespace IPC diff --git a/chromium/ipc/mojo/run_all_perftests.cc b/chromium/ipc/mojo/run_all_perftests.cc new file mode 100644 index 00000000000..a942b8b5749 --- /dev/null +++ b/chromium/ipc/mojo/run_all_perftests.cc @@ -0,0 +1,17 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Copied from mojo/edk/test/run_all_perftests.cc. + +#include "base/command_line.h" +#include "base/test/perf_test_suite.h" +#include "mojo/edk/embedder/embedder.h" + +int main(int argc, char** argv) { + base::PerfTestSuite test(argc, argv); + + mojo::edk::Init(); + + return test.Run(); +} diff --git a/chromium/ipc/mojo/run_all_unittests.cc b/chromium/ipc/mojo/run_all_unittests.cc index 43a1e4e0e8d..4416932e731 100644 --- a/chromium/ipc/mojo/run_all_unittests.cc +++ b/chromium/ipc/mojo/run_all_unittests.cc @@ -5,9 +5,11 @@ #include "base/at_exit.h" #include "base/bind.h" #include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_io_thread.h" #include "base/test/test_suite.h" #include "build/build_config.h" -#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/test/scoped_ipc_support.h" #if defined(OS_ANDROID) #include "base/android/jni_android.h" @@ -20,7 +22,12 @@ int main(int argc, char** argv) { base::RegisterContentUriTestUtils(env); #endif base::TestSuite test_suite(argc, argv); - mojo::embedder::Init(); + mojo::edk::Init(); + base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); + // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which + // really does nothing in the new EDK but does depend on the current message + // loop, which is destructed inside base::LaunchUnitTests. + new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner()); return base::LaunchUnitTestsSerially( argc, argv, base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); diff --git a/chromium/ipc/mojo/scoped_ipc_support.cc b/chromium/ipc/mojo/scoped_ipc_support.cc index 15575444e64..65947bece9c 100644 --- a/chromium/ipc/mojo/scoped_ipc_support.cc +++ b/chromium/ipc/mojo/scoped_ipc_support.cc @@ -4,156 +4,44 @@ #include "ipc/mojo/scoped_ipc_support.h" -#include <stddef.h> - -#include "base/bind.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/thread_task_runner_handle.h" -#include "third_party/mojo/src/mojo/edk/embedder/embedder.h" -#include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/process_delegate.h" namespace IPC { namespace { -// TODO(use_chrome_edk) -//class IPCSupportInitializer : public mojo::edk::ProcessDelegate { -class IPCSupportInitializer : public mojo::embedder::ProcessDelegate { +class IPCSupportInitializer : public mojo::edk::ProcessDelegate { public: - IPCSupportInitializer() - : init_count_(0), - shutting_down_(false), - was_shut_down_(false), - observer_(nullptr) {} - - ~IPCSupportInitializer() override { DCHECK(!observer_); } - - void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner); - void ShutDown(bool force); - - private: - // This watches for destruction of the MessageLoop that IPCSupportInitializer - // uses for IO, and guarantees that the initializer is shut down if it still - // exists when the loop is being destroyed. - class MessageLoopObserver : public base::MessageLoop::DestructionObserver { - public: - MessageLoopObserver(IPCSupportInitializer* initializer) - : initializer_(initializer) {} - - ~MessageLoopObserver() override { - base::MessageLoop::current()->RemoveDestructionObserver(this); - } - - private: - // base::MessageLoop::DestructionObserver: - void WillDestroyCurrentMessageLoop() override { - initializer_->ShutDown(true); - } - - IPCSupportInitializer* initializer_; - - DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver); - }; - - void ShutDownOnIOThread(); - - // mojo::embedder::ProcessDelegate: - void OnShutdownComplete() override {} - - static void WatchMessageLoopOnIOThread(MessageLoopObserver* observer); - - base::Lock lock_; - size_t init_count_; - bool shutting_down_; - - // This is used to track whether shutdown has occurred yet, since we can be - // shut down by either the scoper or IO MessageLoop destruction. - bool was_shut_down_; - - // The message loop destruction observer we have watching our IO loop. This - // is created on the initializer's own thread but is used and destroyed on the - // IO thread. - MessageLoopObserver* observer_; - - scoped_refptr<base::TaskRunner> io_thread_task_runner_; + IPCSupportInitializer() {} + ~IPCSupportInitializer() override {} - DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer); -}; - -void IPCSupportInitializer::Init( - scoped_refptr<base::TaskRunner> io_thread_task_runner) { - base::AutoLock locker(lock_); - DCHECK((init_count_ == 0 && !io_thread_task_runner_) || - io_thread_task_runner_ == io_thread_task_runner); - - if (shutting_down_) { - // If reinitialized before a pending shutdown task is executed, we - // effectively cancel the shutdown task. - DCHECK(init_count_ == 1); - shutting_down_ = false; - return; - } - - init_count_++; - if (init_count_ == 1) { - was_shut_down_ = false; - observer_ = new MessageLoopObserver(this); + void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner) { + CHECK(!io_thread_task_runner_); + CHECK(io_thread_task_runner); io_thread_task_runner_ = io_thread_task_runner; - io_thread_task_runner_->PostTask( - FROM_HERE, base::Bind(&WatchMessageLoopOnIOThread, observer_)); - mojo::embedder::InitIPCSupport( - mojo::embedder::ProcessType::NONE, this, io_thread_task_runner_, - mojo::embedder::ScopedPlatformHandle()); - } -} -void IPCSupportInitializer::ShutDown(bool force) { - base::AutoLock locker(lock_); - if (shutting_down_ || was_shut_down_) - return; - DCHECK(init_count_ > 0); - if (init_count_ > 1 && !force) { - init_count_--; - return; + mojo::edk::InitIPCSupport(this, io_thread_task_runner_); } - shutting_down_ = true; - if (base::MessageLoop::current() && - base::MessageLoop::current()->task_runner() == io_thread_task_runner_) { - base::AutoUnlock unlocker_(lock_); - ShutDownOnIOThread(); - } else { - io_thread_task_runner_->PostTask( - FROM_HERE, base::Bind(&IPCSupportInitializer::ShutDownOnIOThread, - base::Unretained(this))); + void ShutDown() { + CHECK(io_thread_task_runner_); + mojo::edk::ShutdownIPCSupport(); } -} -void IPCSupportInitializer::ShutDownOnIOThread() { - base::AutoLock locker(lock_); - if (shutting_down_ && !was_shut_down_) { - mojo::embedder::ShutdownIPCSupportOnIOThread(); - init_count_ = 0; - shutting_down_ = false; - io_thread_task_runner_ = nullptr; - was_shut_down_ = true; - if (observer_) { - delete observer_; - observer_ = nullptr; - } + private: + // mojo::edk::ProcessDelegate: + void OnShutdownComplete() override { + // TODO(rockot): We should ensure that IO runner shutdown is blocked until + // this is called. } -} -// static -void IPCSupportInitializer::WatchMessageLoopOnIOThread( - MessageLoopObserver* observer) { - base::MessageLoop::current()->AddDestructionObserver(observer); -} + scoped_refptr<base::TaskRunner> io_thread_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer); +}; base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer; @@ -165,7 +53,7 @@ ScopedIPCSupport::ScopedIPCSupport( } ScopedIPCSupport::~ScopedIPCSupport() { - ipc_support_initializer.Get().ShutDown(false); + ipc_support_initializer.Get().ShutDown(); } } // namespace IPC diff --git a/chromium/ipc/mojo/scoped_ipc_support.h b/chromium/ipc/mojo/scoped_ipc_support.h index 21013fa75c0..29c50bf4a48 100644 --- a/chromium/ipc/mojo/scoped_ipc_support.h +++ b/chromium/ipc/mojo/scoped_ipc_support.h @@ -12,14 +12,12 @@ namespace IPC { -// Perform any necessary Mojo IPC initialization. A ScopedIPCSupport object -// should be instantiated and retained by any component which makes direct calls -// to the Mojo EDK. This is used to ensure that the EDK is initialized within -// the current process and that it is shutdown cleanly when no longer in use. +// Performs any necessary Mojo IPC initialization on construction, and shuts +// down Mojo IPC on destruction. // -// NOTE: Unless you are making explicit calls to functions in the -// mojo::embedder namespace, you almost definitely DO NOT need this and should -// not be using it. +// This should be instantiated once per process and retained as long as Mojo IPC +// is needed. The TaskRunner passed to the constructor should outlive this +// object. class IPC_MOJO_EXPORT ScopedIPCSupport { public: ScopedIPCSupport(scoped_refptr<base::TaskRunner> io_thread_task_runner); diff --git a/chromium/ipc/param_traits_macros.h b/chromium/ipc/param_traits_macros.h index 317f31228d9..10034402382 100644 --- a/chromium/ipc/param_traits_macros.h +++ b/chromium/ipc/param_traits_macros.h @@ -8,16 +8,19 @@ #include <string> // Traits generation for structs. -#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \ - namespace IPC { \ - template <> \ - struct IPC_MESSAGE_EXPORT ParamTraits<struct_name> { \ - typedef struct_name param_type; \ - static void Write(Message* m, const param_type& p); \ - static bool Read(const Message* m, base::PickleIterator* iter, \ - param_type* p); \ - static void Log(const param_type& p, std::string* l); \ - }; \ +#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \ + namespace IPC { \ + template <> \ + struct IPC_MESSAGE_EXPORT ParamTraits<struct_name> { \ + typedef struct_name param_type; \ + static void GetSize(base::PickleSizer* sizer, \ + const param_type& p); \ + static void Write(base::Pickle* m, const param_type& p); \ + static bool Read(const base::Pickle* m, \ + base::PickleIterator* iter, \ + param_type* p); \ + static void Log(const param_type& p, std::string* l); \ + }; \ } #define IPC_STRUCT_TRAITS_MEMBER(name) @@ -48,15 +51,18 @@ // Traits generation for enums. This macro may be redefined later. #define IPC_ENUM_TRAITS_VALIDATE(enum_name, validation_expression) \ - namespace IPC { \ - template <> \ - struct IPC_MESSAGE_EXPORT ParamTraits<enum_name> { \ - typedef enum_name param_type; \ - static void Write(Message* m, const param_type& p); \ - static bool Read(const Message* m, base::PickleIterator* iter, \ - param_type* p); \ - static void Log(const param_type& p, std::string* l); \ - }; \ + namespace IPC { \ + template <> \ + struct IPC_MESSAGE_EXPORT ParamTraits<enum_name> { \ + typedef enum_name param_type; \ + static void GetSize(base::PickleSizer* sizer, \ + const param_type& p); \ + static void Write(base::Pickle* m, const param_type& p); \ + static bool Read(const base::Pickle* m, \ + base::PickleIterator* iter, \ + param_type* p); \ + static void Log(const param_type& p, std::string* l); \ + }; \ } #endif // IPC_PARAM_TRAITS_MACROS_H_ diff --git a/chromium/ipc/param_traits_read_macros.h b/chromium/ipc/param_traits_read_macros.h index a66c89a8d0e..45e635285a9 100644 --- a/chromium/ipc/param_traits_read_macros.h +++ b/chromium/ipc/param_traits_read_macros.h @@ -22,25 +22,25 @@ #undef IPC_STRUCT_TRAITS_MEMBER #undef IPC_STRUCT_TRAITS_PARENT #undef IPC_STRUCT_TRAITS_END -#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \ - bool ParamTraits<struct_name>:: \ - Read(const Message* m, base::PickleIterator* iter, param_type* p) { \ - return +#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \ + bool ParamTraits<struct_name>::Read( \ + const base::Pickle* m, base::PickleIterator* iter, param_type* p) { \ + return #define IPC_STRUCT_TRAITS_MEMBER(name) ReadParam(m, iter, &p->name) && #define IPC_STRUCT_TRAITS_PARENT(type) ParamTraits<type>::Read(m, iter, p) && #define IPC_STRUCT_TRAITS_END() 1; } #undef IPC_ENUM_TRAITS_VALIDATE -#define IPC_ENUM_TRAITS_VALIDATE(enum_name, validation_expression) \ - bool ParamTraits<enum_name>:: \ - Read(const Message* m, base::PickleIterator* iter, param_type* p) { \ - int value; \ - if (!iter->ReadInt(&value)) \ - return false; \ - if (!(validation_expression)) \ - return false; \ - *p = static_cast<param_type>(value); \ - return true; \ +#define IPC_ENUM_TRAITS_VALIDATE(enum_name, validation_expression) \ + bool ParamTraits<enum_name>::Read( \ + const base::Pickle* m, base::PickleIterator* iter, param_type* p) { \ + int value; \ + if (!iter->ReadInt(&value)) \ + return false; \ + if (!(validation_expression)) \ + return false; \ + *p = static_cast<param_type>(value); \ + return true; \ } #endif // IPC_PARAM_TRAITS_READ_MACROS_H_ diff --git a/chromium/ipc/param_traits_size_macros.h b/chromium/ipc/param_traits_size_macros.h new file mode 100644 index 00000000000..142b55a32d6 --- /dev/null +++ b/chromium/ipc/param_traits_size_macros.h @@ -0,0 +1,40 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IPC_PARAM_TRAITS_SIZE_MACROS_H_ +#define IPC_PARAM_TRAITS_SIZE_MACROS_H_ + +// Null out all the macros that need nulling. +#include "ipc/ipc_message_null_macros.h" + +// STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur. +#undef IPC_STRUCT_BEGIN_WITH_PARENT +#undef IPC_STRUCT_MEMBER +#undef IPC_STRUCT_END +#define IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, parent) \ + IPC_STRUCT_TRAITS_BEGIN(struct_name) +#define IPC_STRUCT_MEMBER(type, name, ...) IPC_STRUCT_TRAITS_MEMBER(name) +#define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END() + +// Set up so next include will generate size methods. +#undef IPC_STRUCT_TRAITS_BEGIN +#undef IPC_STRUCT_TRAITS_MEMBER +#undef IPC_STRUCT_TRAITS_PARENT +#undef IPC_STRUCT_TRAITS_END +#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \ + void ParamTraits<struct_name>::GetSize(base::PickleSizer* sizer, \ + const param_type& p) { +#define IPC_STRUCT_TRAITS_MEMBER(name) GetParamSize(sizer, p.name); +#define IPC_STRUCT_TRAITS_PARENT(type) ParamTraits<type>::GetSize(sizer, p); +#define IPC_STRUCT_TRAITS_END() } + +#undef IPC_ENUM_TRAITS_VALIDATE +#define IPC_ENUM_TRAITS_VALIDATE(enum_name, validation_expression) \ + void ParamTraits<enum_name>::GetSize(base::PickleSizer* sizer, \ + const param_type& value) { \ + sizer->AddInt(); \ + } + +#endif // IPC_PARAM_TRAITS_SIZE_MACROS_H_ + diff --git a/chromium/ipc/param_traits_write_macros.h b/chromium/ipc/param_traits_write_macros.h index 81f915ffff8..a1aca4374eb 100644 --- a/chromium/ipc/param_traits_write_macros.h +++ b/chromium/ipc/param_traits_write_macros.h @@ -23,16 +23,17 @@ #undef IPC_STRUCT_TRAITS_PARENT #undef IPC_STRUCT_TRAITS_END #define IPC_STRUCT_TRAITS_BEGIN(struct_name) \ - void ParamTraits<struct_name>::Write(Message* m, const param_type& p) { + void ParamTraits<struct_name>::Write(base::Pickle* m, const param_type& p) { #define IPC_STRUCT_TRAITS_MEMBER(name) WriteParam(m, p.name); #define IPC_STRUCT_TRAITS_PARENT(type) ParamTraits<type>::Write(m, p); #define IPC_STRUCT_TRAITS_END() } #undef IPC_ENUM_TRAITS_VALIDATE #define IPC_ENUM_TRAITS_VALIDATE(enum_name, validation_expression) \ - void ParamTraits<enum_name>::Write(Message* m, const param_type& value) { \ - DCHECK(validation_expression); \ - m->WriteInt(static_cast<int>(value)); \ + void ParamTraits<enum_name>::Write(base::Pickle* m, \ + const param_type& value) { \ + DCHECK(validation_expression); \ + m->WriteInt(static_cast<int>(value)); \ } #endif // IPC_PARAM_TRAITS_WRITE_MACROS_H_ diff --git a/chromium/ipc/unix_domain_socket_util.cc b/chromium/ipc/unix_domain_socket_util.cc index fb64cb29165..ee82560bddb 100644 --- a/chromium/ipc/unix_domain_socket_util.cc +++ b/chromium/ipc/unix_domain_socket_util.cc @@ -5,10 +5,7 @@ #include "ipc/unix_domain_socket_util.h" #include <errno.h> -#include <fcntl.h> -#include <stddef.h> #include <sys/socket.h> -#include <sys/stat.h> #include <sys/un.h> #include <unistd.h> @@ -27,37 +24,25 @@ static_assert(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxSocketNameLength, namespace { -// Returns fd (>= 0) on success, -1 on failure. If successful, fills in -// |unix_addr| with the appropriate data for the socket, and sets -// |unix_addr_len| to the length of the data therein. -int MakeUnixAddrForPath(const std::string& socket_name, - struct sockaddr_un* unix_addr, - size_t* unix_addr_len) { +// This function fills in |unix_addr| with the appropriate data for the socket, +// and sets |unix_addr_len| to the length of the data therein. +// Returns true on success, or false on failure (typically because |socket_name| +// violated the naming rules). +bool MakeUnixAddrForPath(const std::string& socket_name, + struct sockaddr_un* unix_addr, + size_t* unix_addr_len) { DCHECK(unix_addr); DCHECK(unix_addr_len); if (socket_name.length() == 0) { LOG(ERROR) << "Empty socket name provided for unix socket address."; - return -1; + return false; } // We reject socket_name.length() == kMaxSocketNameLength to make room for // the NUL terminator at the end of the string. if (socket_name.length() >= kMaxSocketNameLength) { LOG(ERROR) << "Socket name too long: " << socket_name; - return -1; - } - - // Create socket. - base::ScopedFD fd(socket(AF_UNIX, SOCK_STREAM, 0)); - if (!fd.is_valid()) { - PLOG(ERROR) << "socket"; - return -1; - } - - // Make socket non-blocking - if (HANDLE_EINTR(fcntl(fd.get(), F_SETFL, O_NONBLOCK)) < 0) { - PLOG(ERROR) << "fcntl(O_NONBLOCK)"; - return -1; + return false; } // Create unix_addr structure. @@ -66,7 +51,36 @@ int MakeUnixAddrForPath(const std::string& socket_name, strncpy(unix_addr->sun_path, socket_name.c_str(), kMaxSocketNameLength); *unix_addr_len = offsetof(struct sockaddr_un, sun_path) + socket_name.length(); - return fd.release(); + return true; +} + +// This functions creates a unix domain socket, and set it as non-blocking. +// If successful, |out_fd| will be set to the new file descriptor, and the +// function will return true. Otherwise returns false. +bool CreateUnixDomainSocket(base::ScopedFD* out_fd) { + DCHECK(out_fd); + + // Create the unix domain socket. + base::ScopedFD fd(socket(AF_UNIX, SOCK_STREAM, 0)); + if (!fd.is_valid()) { + PLOG(ERROR) << "Failed to create AF_UNIX socket."; + return false; + } + + // Now set it as non-blocking. + if (!base::SetNonBlocking(fd.get())) { + PLOG(ERROR) << "base::SetNonBlocking() failed " << fd.get(); + return false; + } + + fd.swap(*out_fd); + + return true; +} + +bool IsRecoverableError() { + return errno == ECONNABORTED || errno == EMFILE || errno == ENFILE || + errno == ENOMEM || errno == ENOBUFS; } } // namespace @@ -75,38 +89,40 @@ bool CreateServerUnixDomainSocket(const base::FilePath& socket_path, int* server_listen_fd) { DCHECK(server_listen_fd); - std::string socket_name = socket_path.value(); - base::FilePath socket_dir = socket_path.DirName(); - - struct sockaddr_un unix_addr; - size_t unix_addr_len; - base::ScopedFD fd( - MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len)); - if (!fd.is_valid()) - return false; - // Make sure the path we need exists. + base::FilePath socket_dir = socket_path.DirName(); if (!base::CreateDirectory(socket_dir)) { LOG(ERROR) << "Couldn't create directory: " << socket_dir.value(); return false; } + const std::string socket_name = socket_path.value(); + // Delete any old FS instances. if (unlink(socket_name.c_str()) < 0 && errno != ENOENT) { PLOG(ERROR) << "unlink " << socket_name; return false; } + struct sockaddr_un unix_addr; + size_t unix_addr_len; + if (!MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len)) + return false; + + base::ScopedFD fd; + if (!CreateUnixDomainSocket(&fd)) + return false; + // Bind the socket. if (bind(fd.get(), reinterpret_cast<const sockaddr*>(&unix_addr), unix_addr_len) < 0) { - PLOG(ERROR) << "bind " << socket_path.value(); + PLOG(ERROR) << "bind " << socket_name; return false; } // Start listening on the socket. if (listen(fd.get(), SOMAXCONN) < 0) { - PLOG(ERROR) << "listen " << socket_path.value(); + PLOG(ERROR) << "listen " << socket_name; unlink(socket_name.c_str()); return false; } @@ -119,14 +135,13 @@ bool CreateClientUnixDomainSocket(const base::FilePath& socket_path, int* client_socket) { DCHECK(client_socket); - std::string socket_name = socket_path.value(); - base::FilePath socket_dir = socket_path.DirName(); - struct sockaddr_un unix_addr; size_t unix_addr_len; - base::ScopedFD fd( - MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len)); - if (!fd.is_valid()) + if (!MakeUnixAddrForPath(socket_path.value(), &unix_addr, &unix_addr_len)) + return false; + + base::ScopedFD fd; + if (!CreateUnixDomainSocket(&fd)) return false; if (HANDLE_EINTR(connect(fd.get(), reinterpret_cast<sockaddr*>(&unix_addr), @@ -177,20 +192,16 @@ bool IsPeerAuthorized(int peer_fd) { return true; } -bool IsRecoverableError(int err) { - return errno == ECONNABORTED || errno == EMFILE || errno == ENFILE || - errno == ENOMEM || errno == ENOBUFS; -} - bool ServerAcceptConnection(int server_listen_fd, int* server_socket) { DCHECK(server_socket); *server_socket = -1; base::ScopedFD accept_fd(HANDLE_EINTR(accept(server_listen_fd, NULL, 0))); if (!accept_fd.is_valid()) - return IsRecoverableError(errno); - if (HANDLE_EINTR(fcntl(accept_fd.get(), F_SETFL, O_NONBLOCK)) < 0) { - PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd.get(); + return IsRecoverableError(); + + if (!base::SetNonBlocking(accept_fd.get())) { + PLOG(ERROR) << "base::SetNonBlocking() failed " << accept_fd.get(); // It's safe to keep listening on |server_listen_fd| even if the attempt to // set O_NONBLOCK failed on the client fd. return true; diff --git a/chromium/ipc/unix_domain_socket_util.h b/chromium/ipc/unix_domain_socket_util.h index 13590722950..78d98644cb9 100644 --- a/chromium/ipc/unix_domain_socket_util.h +++ b/chromium/ipc/unix_domain_socket_util.h @@ -8,8 +8,6 @@ #include <stddef.h> #include <sys/types.h> -#include <string> - #include "ipc/ipc_export.h" namespace base { diff --git a/chromium/ipc/unix_domain_socket_util_unittest.cc b/chromium/ipc/unix_domain_socket_util_unittest.cc index 49c1c024c1f..2ba8cfe5a72 100644 --- a/chromium/ipc/unix_domain_socket_util_unittest.cc +++ b/chromium/ipc/unix_domain_socket_util_unittest.cc @@ -9,6 +9,7 @@ #include "base/files/file_path.h" #include "base/location.h" #include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "base/path_service.h" #include "base/posix/eintr_wrapper.h" #include "base/single_thread_task_runner.h" |