summaryrefslogtreecommitdiff
path: root/chromium/ipc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-06-18 14:10:49 +0200
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2015-06-18 13:53:24 +0000
commit813fbf95af77a531c57a8c497345ad2c61d475b3 (patch)
tree821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/ipc
parentaf6588f8d723931a298c995fa97259bb7f7deb55 (diff)
downloadqtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/ipc')
-rw-r--r--chromium/ipc/BUILD.gn40
-rw-r--r--chromium/ipc/file_descriptor_set_posix.cc162
-rw-r--r--chromium/ipc/file_descriptor_set_posix_unittest.cc183
-rw-r--r--chromium/ipc/ipc.gyp4
-rw-r--r--chromium/ipc/ipc.gypi8
-rw-r--r--chromium/ipc/ipc_channel.cc7
-rw-r--r--chromium/ipc/ipc_channel.h6
-rw-r--r--chromium/ipc/ipc_channel_common.cc4
-rw-r--r--chromium/ipc/ipc_channel_nacl.cc66
-rw-r--r--chromium/ipc/ipc_channel_nacl.h24
-rw-r--r--chromium/ipc/ipc_channel_posix.cc80
-rw-r--r--chromium/ipc/ipc_channel_posix.h8
-rw-r--r--chromium/ipc/ipc_channel_posix_unittest.cc54
-rw-r--r--chromium/ipc/ipc_channel_proxy.cc75
-rw-r--r--chromium/ipc/ipc_channel_proxy.h59
-rw-r--r--chromium/ipc/ipc_channel_proxy_unittest.cc18
-rw-r--r--chromium/ipc/ipc_channel_unittest.cc25
-rw-r--r--chromium/ipc/ipc_channel_win.cc79
-rw-r--r--chromium/ipc/ipc_channel_win.h38
-rw-r--r--chromium/ipc/ipc_fuzzing_tests.cc59
-rw-r--r--chromium/ipc/ipc_logging.cc10
-rw-r--r--chromium/ipc/ipc_message.cc64
-rw-r--r--chromium/ipc/ipc_message.h56
-rw-r--r--chromium/ipc/ipc_message_attachment.cc15
-rw-r--r--chromium/ipc/ipc_message_attachment.h41
-rw-r--r--chromium/ipc/ipc_message_attachment_set.cc163
-rw-r--r--chromium/ipc/ipc_message_attachment_set.h (renamed from chromium/ipc/file_descriptor_set_posix.h)111
-rw-r--r--chromium/ipc/ipc_message_attachment_set_posix_unittest.cc201
-rw-r--r--chromium/ipc/ipc_message_macros.h40
-rw-r--r--chromium/ipc/ipc_message_start.h19
-rw-r--r--chromium/ipc/ipc_message_utils.cc57
-rw-r--r--chromium/ipc/ipc_message_utils.h194
-rw-r--r--chromium/ipc/ipc_nacl.gyp2
-rw-r--r--chromium/ipc/ipc_perftest_support.cc47
-rw-r--r--chromium/ipc/ipc_perftest_support.h21
-rw-r--r--chromium/ipc/ipc_platform_file_attachment_posix.cc37
-rw-r--r--chromium/ipc/ipc_platform_file_attachment_posix.h43
-rw-r--r--chromium/ipc/ipc_security_test_util.cc25
-rw-r--r--chromium/ipc/ipc_security_test_util.h40
-rw-r--r--chromium/ipc/ipc_send_fds_test.cc72
-rw-r--r--chromium/ipc/ipc_sync_channel.cc2
-rw-r--r--chromium/ipc/ipc_sync_channel_unittest.cc95
-rw-r--r--chromium/ipc/ipc_sync_message.cc2
-rw-r--r--chromium/ipc/ipc_sync_message_filter.cc24
-rw-r--r--chromium/ipc/ipc_sync_message_filter.h6
-rw-r--r--chromium/ipc/ipc_test_base.cc28
-rw-r--r--chromium/ipc/ipc_test_base.h12
-rw-r--r--chromium/ipc/ipc_test_sink.cc2
-rw-r--r--chromium/ipc/mojo/BUILD.gn30
-rw-r--r--chromium/ipc/mojo/DEPS4
-rw-r--r--chromium/ipc/mojo/async_handle_waiter.cc165
-rw-r--r--chromium/ipc/mojo/async_handle_waiter.h52
-rw-r--r--chromium/ipc/mojo/async_handle_waiter_unittest.cc257
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo.cc381
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo.h89
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo_host.cc53
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo_host.h17
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo_readers.cc84
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo_readers.h96
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo_unittest.cc496
-rw-r--r--chromium/ipc/mojo/ipc_message_pipe_reader.cc222
-rw-r--r--chromium/ipc/mojo/ipc_message_pipe_reader.h46
-rw-r--r--chromium/ipc/mojo/ipc_mojo.gyp27
-rw-r--r--chromium/ipc/mojo/ipc_mojo_bootstrap.cc25
-rw-r--r--chromium/ipc/mojo/ipc_mojo_bootstrap.h8
-rw-r--r--chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc2
-rw-r--r--chromium/ipc/mojo/ipc_mojo_handle_attachment.cc43
-rw-r--r--chromium/ipc/mojo/ipc_mojo_handle_attachment.h50
-rw-r--r--chromium/ipc/mojo/ipc_mojo_message_helper.cc47
-rw-r--r--chromium/ipc/mojo/ipc_mojo_message_helper.h29
-rw-r--r--chromium/ipc/mojo/ipc_mojo_param_traits.cc43
-rw-r--r--chromium/ipc/mojo/ipc_mojo_param_traits.h30
-rw-r--r--chromium/ipc/mojo/ipc_mojo_perftest.cc44
-rw-r--r--chromium/ipc/mojo/run_all_unittests.cc2
-rw-r--r--chromium/ipc/mojo/scoped_ipc_support.cc178
-rw-r--r--chromium/ipc/mojo/scoped_ipc_support.h34
-rw-r--r--chromium/ipc/param_traits_read_macros.h2
-rw-r--r--chromium/ipc/sync_socket_unittest.cc16
-rw-r--r--chromium/ipc/unix_domain_socket_util.cc4
-rw-r--r--chromium/ipc/unix_domain_socket_util_unittest.cc16
80 files changed, 3410 insertions, 1610 deletions
diff --git a/chromium/ipc/BUILD.gn b/chromium/ipc/BUILD.gn
index e7e08b5aadd..b756921e7dd 100644
--- a/chromium/ipc/BUILD.gn
+++ b/chromium/ipc/BUILD.gn
@@ -2,15 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//testing/test.gni")
+
component("ipc") {
sources = [
- "file_descriptor_set_posix.cc",
- "file_descriptor_set_posix.h",
"ipc_channel.cc",
"ipc_channel.h",
+ "ipc_channel_common.cc",
"ipc_channel_factory.cc",
"ipc_channel_factory.h",
- "ipc_channel_common.cc",
"ipc_channel_handle.h",
"ipc_channel_nacl.cc",
"ipc_channel_nacl.h",
@@ -31,6 +31,10 @@ component("ipc") {
"ipc_logging.h",
"ipc_message.cc",
"ipc_message.h",
+ "ipc_message_attachment.cc",
+ "ipc_message_attachment.h",
+ "ipc_message_attachment_set.cc",
+ "ipc_message_attachment_set.h",
"ipc_message_macros.h",
"ipc_message_start.h",
"ipc_message_utils.cc",
@@ -38,6 +42,8 @@ component("ipc") {
"ipc_param_traits.h",
"ipc_platform_file.cc",
"ipc_platform_file.h",
+ "ipc_platform_file_attachment_posix.cc",
+ "ipc_platform_file_attachment_posix.h",
"ipc_sender.h",
"ipc_switches.cc",
"ipc_switches.h",
@@ -61,7 +67,13 @@ component("ipc") {
"unix_domain_socket_util.h",
]
- if (!is_nacl) {
+ if (is_nacl) {
+ sources -= [
+ "ipc_channel.cc",
+ "ipc_channel_posix.cc",
+ "unix_domain_socket_util.cc",
+ ]
+ } else {
sources -= [
"ipc_channel_nacl.cc",
"ipc_channel_nacl.h",
@@ -69,28 +81,27 @@ component("ipc") {
}
if (is_win || is_ios) {
- sources -= [
- "unix_domain_socket_util.cc",
- ]
+ sources -= [ "unix_domain_socket_util.cc" ]
}
defines = [ "IPC_IMPLEMENTATION" ]
deps = [
"//base",
+
# TODO(viettrungluu): Needed for base/lazy_instance.h, which is suspect.
"//base/third_party/dynamic_annotations",
]
}
-# TODO(dpranke): crbug.com/360936. Get this to build and run on Android.
+# TODO(GYP): crbug.com/360936. Get this to build and run on Android.
if (!is_android) {
test("ipc_tests") {
sources = [
- "file_descriptor_set_posix_unittest.cc",
"ipc_channel_posix_unittest.cc",
"ipc_channel_unittest.cc",
"ipc_fuzzing_tests.cc",
+ "ipc_message_attachment_set_posix_unittest.cc",
"ipc_message_unittest.cc",
"ipc_message_utils_unittest.cc",
"ipc_send_fds_test.cc",
@@ -144,7 +155,6 @@ if (!is_android) {
# deps += "//base/allocator"
# }
#}
-
deps = [
":ipc",
":test_support",
@@ -164,17 +174,19 @@ static_library("test_support") {
"ipc_multiprocess_test.h",
"ipc_perftest_support.cc",
"ipc_perftest_support.h",
- "ipc_test_sink.cc",
- "ipc_test_sink.h",
+ "ipc_security_test_util.cc",
+ "ipc_security_test_util.h",
"ipc_test_base.cc",
"ipc_test_base.h",
- "ipc_test_channel_listener.h",
"ipc_test_channel_listener.cc",
+ "ipc_test_channel_listener.h",
+ "ipc_test_sink.cc",
+ "ipc_test_sink.h",
]
deps = [
":ipc",
"//base",
+ "//base/test:test_support",
"//testing/gtest",
]
}
-
diff --git a/chromium/ipc/file_descriptor_set_posix.cc b/chromium/ipc/file_descriptor_set_posix.cc
deleted file mode 100644
index 568fee3323c..00000000000
--- a/chromium/ipc/file_descriptor_set_posix.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-// 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/file_descriptor_set_posix.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
-
-FileDescriptorSet::FileDescriptorSet()
- : consumed_descriptor_highwater_(0) {
-}
-
-FileDescriptorSet::~FileDescriptorSet() {
- if (consumed_descriptor_highwater_ == size())
- return;
-
- // We close all the owning descriptors. If this message should have
- // been transmitted, then closing those with close flags set mirrors
- // the expected behaviour.
- //
- // If this message was received with more descriptors than expected
- // (which could a DOS against the browser by a rogue renderer) then all
- // the descriptors have their close flag set and we free all the extra
- // kernel resources.
- LOG(WARNING) << "FileDescriptorSet destroyed with unconsumed descriptors: "
- << consumed_descriptor_highwater_ << "/" << size();
-}
-
-bool FileDescriptorSet::AddToBorrow(base::PlatformFile fd) {
- DCHECK_EQ(consumed_descriptor_highwater_, 0u);
-
- if (size() == kMaxDescriptorsPerMessage) {
- DLOG(WARNING) << "Cannot add file descriptor. FileDescriptorSet full.";
- return false;
- }
-
- descriptors_.push_back(fd);
- return true;
-}
-
-bool FileDescriptorSet::AddToOwn(base::ScopedFD fd) {
- DCHECK_EQ(consumed_descriptor_highwater_, 0u);
-
- if (size() == kMaxDescriptorsPerMessage) {
- DLOG(WARNING) << "Cannot add file descriptor. FileDescriptorSet full.";
- return false;
- }
-
- descriptors_.push_back(fd.get());
- owned_descriptors_.push_back(new base::ScopedFD(fd.Pass()));
- DCHECK(size() <= kMaxDescriptorsPerMessage);
- return true;
-}
-
-base::PlatformFile FileDescriptorSet::TakeDescriptorAt(unsigned index) {
- if (index >= size()) {
- DLOG(WARNING) << "Accessing out of bound index:"
- << index << "/" << size();
- return -1;
- }
-
-
- // We should always walk the descriptors in order, so it's reasonable to
- // enforce this. Consider the case where a compromised renderer sends us
- // the following message:
- //
- // ExampleMsg:
- // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
- //
- // Here the renderer sent us a message which should have a descriptor, but
- // actually sent two in an attempt to fill our fd table and kill us. By
- // setting the index of the descriptor in the message to 1 (it should be
- // 0), we would record a highwater of 1 and then consider all the
- // descriptors to have been used.
- //
- // So we can either track of the use of each descriptor in a bitset, or we
- // can enforce that we walk the indexes strictly in order.
- //
- // There's one more wrinkle: When logging messages, we may reparse them. So
- // we have an exception: When the consumed_descriptor_highwater_ is at the
- // end of the array and index 0 is requested, we reset the highwater value.
- // TODO(morrita): This is absurd. This "wringle" disallow to introduce clearer
- // ownership model. Only client is NaclIPCAdapter. See crbug.com/415294
- if (index == 0 && consumed_descriptor_highwater_ == descriptors_.size())
- consumed_descriptor_highwater_ = 0;
-
- if (index != consumed_descriptor_highwater_)
- return -1;
-
- consumed_descriptor_highwater_ = index + 1;
-
- base::PlatformFile file = descriptors_[index];
-
- // TODO(morrita): In production, descriptors_.size() should be same as
- // owned_descriptors_.size() as all read descriptors are owned by Message.
- // We have to do this because unit test breaks this assumption. It should be
- // changed to exercise with own-able descriptors.
- for (ScopedVector<base::ScopedFD>::const_iterator i =
- owned_descriptors_.begin();
- i != owned_descriptors_.end();
- ++i) {
- if ((*i)->get() == file) {
- ignore_result((*i)->release());
- break;
- }
- }
-
- return file;
-}
-
-void FileDescriptorSet::PeekDescriptors(base::PlatformFile* buffer) const {
- std::copy(descriptors_.begin(), descriptors_.end(), buffer);
-}
-
-bool FileDescriptorSet::ContainsDirectoryDescriptor() const {
- struct stat st;
-
- for (std::vector<base::PlatformFile>::const_iterator i = descriptors_.begin();
- i != descriptors_.end();
- ++i) {
- if (fstat(*i, &st) == 0 && S_ISDIR(st.st_mode))
- return true;
- }
-
- return false;
-}
-
-void FileDescriptorSet::CommitAll() {
- descriptors_.clear();
- owned_descriptors_.clear();
- consumed_descriptor_highwater_ = 0;
-}
-
-void FileDescriptorSet::ReleaseFDsToClose(
- std::vector<base::PlatformFile>* fds) {
- for (ScopedVector<base::ScopedFD>::iterator i = owned_descriptors_.begin();
- i != owned_descriptors_.end();
- ++i) {
- fds->push_back((*i)->release());
- }
-
- CommitAll();
-}
-
-void FileDescriptorSet::AddDescriptorsToOwn(const base::PlatformFile* buffer,
- unsigned count) {
- DCHECK(count <= kMaxDescriptorsPerMessage);
- DCHECK_EQ(size(), 0u);
- DCHECK_EQ(consumed_descriptor_highwater_, 0u);
-
- descriptors_.reserve(count);
- owned_descriptors_.reserve(count);
- for (unsigned i = 0; i < count; ++i) {
- descriptors_.push_back(buffer[i]);
- owned_descriptors_.push_back(new base::ScopedFD(buffer[i]));
- }
-}
diff --git a/chromium/ipc/file_descriptor_set_posix_unittest.cc b/chromium/ipc/file_descriptor_set_posix_unittest.cc
deleted file mode 100644
index 34ef465edc0..00000000000
--- a/chromium/ipc/file_descriptor_set_posix_unittest.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-// 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.
-
-// This test is POSIX only.
-
-#include "ipc/file_descriptor_set_posix.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "base/basictypes.h"
-#include "base/posix/eintr_wrapper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// Get a safe file descriptor for test purposes.
-int GetSafeFd() {
- return open("/dev/null", O_RDONLY);
-}
-
-// Returns true if fd was already closed. Closes fd if not closed.
-bool VerifyClosed(int fd) {
- const int duped = dup(fd);
- if (duped != -1) {
- EXPECT_NE(IGNORE_EINTR(close(duped)), -1);
- EXPECT_NE(IGNORE_EINTR(close(fd)), -1);
- return false;
- }
- return true;
-}
-
-// The FileDescriptorSet will try and close some of the descriptor numbers
-// which we given it. This is the base descriptor value. It's great enough such
-// that no real descriptor will accidently be closed.
-static const int kFDBase = 50000;
-
-TEST(FileDescriptorSet, BasicAdd) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- ASSERT_EQ(set->size(), 0u);
- ASSERT_TRUE(set->empty());
- ASSERT_TRUE(set->AddToBorrow(kFDBase));
- ASSERT_EQ(set->size(), 1u);
- ASSERT_TRUE(!set->empty());
-
- // Empties the set and stops a warning about deleting a set with unconsumed
- // descriptors
- set->CommitAll();
-}
-
-TEST(FileDescriptorSet, BasicAddAndClose) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- ASSERT_EQ(set->size(), 0u);
- ASSERT_TRUE(set->empty());
- const int fd = GetSafeFd();
- ASSERT_TRUE(set->AddToOwn(base::ScopedFD(fd)));
- ASSERT_EQ(set->size(), 1u);
- ASSERT_TRUE(!set->empty());
-
- set->CommitAll();
-
- ASSERT_TRUE(VerifyClosed(fd));
-}
-TEST(FileDescriptorSet, MaxSize) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- for (size_t i = 0; i < FileDescriptorSet::kMaxDescriptorsPerMessage; ++i)
- ASSERT_TRUE(set->AddToBorrow(kFDBase + 1 + i));
-
- ASSERT_TRUE(!set->AddToBorrow(kFDBase));
-
- set->CommitAll();
-}
-
-TEST(FileDescriptorSet, SetDescriptors) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- ASSERT_TRUE(set->empty());
- set->AddDescriptorsToOwn(NULL, 0);
- ASSERT_TRUE(set->empty());
-
- const int fd = GetSafeFd();
- static const int fds[] = {fd};
- set->AddDescriptorsToOwn(fds, 1);
- ASSERT_TRUE(!set->empty());
- ASSERT_EQ(set->size(), 1u);
-
- set->CommitAll();
-
- ASSERT_TRUE(VerifyClosed(fd));
-}
-
-TEST(FileDescriptorSet, PeekDescriptors) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- set->PeekDescriptors(NULL);
- ASSERT_TRUE(set->AddToBorrow(kFDBase));
-
- int fds[1];
- fds[0] = 0;
- set->PeekDescriptors(fds);
- ASSERT_EQ(fds[0], kFDBase);
- set->CommitAll();
- ASSERT_TRUE(set->empty());
-}
-
-TEST(FileDescriptorSet, WalkInOrder) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
- // used to retrieve borrowed descriptors. That never happens in production.
- ASSERT_TRUE(set->AddToBorrow(kFDBase));
- ASSERT_TRUE(set->AddToBorrow(kFDBase + 1));
- ASSERT_TRUE(set->AddToBorrow(kFDBase + 2));
-
- ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
- ASSERT_EQ(set->TakeDescriptorAt(1), kFDBase + 1);
- ASSERT_EQ(set->TakeDescriptorAt(2), kFDBase + 2);
-
- set->CommitAll();
-}
-
-TEST(FileDescriptorSet, WalkWrongOrder) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
- // used to retrieve borrowed descriptors. That never happens in production.
- ASSERT_TRUE(set->AddToBorrow(kFDBase));
- ASSERT_TRUE(set->AddToBorrow(kFDBase + 1));
- ASSERT_TRUE(set->AddToBorrow(kFDBase + 2));
-
- ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
- ASSERT_EQ(set->TakeDescriptorAt(2), -1);
-
- set->CommitAll();
-}
-
-TEST(FileDescriptorSet, WalkCycle) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
- // used to retrieve borrowed descriptors. That never happens in production.
- ASSERT_TRUE(set->AddToBorrow(kFDBase));
- ASSERT_TRUE(set->AddToBorrow(kFDBase + 1));
- ASSERT_TRUE(set->AddToBorrow(kFDBase + 2));
-
- ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
- ASSERT_EQ(set->TakeDescriptorAt(1), kFDBase + 1);
- ASSERT_EQ(set->TakeDescriptorAt(2), kFDBase + 2);
- ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
- ASSERT_EQ(set->TakeDescriptorAt(1), kFDBase + 1);
- ASSERT_EQ(set->TakeDescriptorAt(2), kFDBase + 2);
- ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
- ASSERT_EQ(set->TakeDescriptorAt(1), kFDBase + 1);
- ASSERT_EQ(set->TakeDescriptorAt(2), kFDBase + 2);
-
- set->CommitAll();
-}
-
-TEST(FileDescriptorSet, DontClose) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- const int fd = GetSafeFd();
- ASSERT_TRUE(set->AddToBorrow(fd));
- set->CommitAll();
-
- ASSERT_FALSE(VerifyClosed(fd));
-}
-
-TEST(FileDescriptorSet, DoClose) {
- scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
-
- const int fd = GetSafeFd();
- ASSERT_TRUE(set->AddToOwn(base::ScopedFD(fd)));
- set->CommitAll();
-
- ASSERT_TRUE(VerifyClosed(fd));
-}
-
-} // namespace
diff --git a/chromium/ipc/ipc.gyp b/chromium/ipc/ipc.gyp
index 28c112b0ba6..1a28fc26c9a 100644
--- a/chromium/ipc/ipc.gyp
+++ b/chromium/ipc/ipc.gyp
@@ -44,11 +44,11 @@
'..'
],
'sources': [
- 'file_descriptor_set_posix_unittest.cc',
'ipc_channel_posix_unittest.cc',
'ipc_channel_proxy_unittest.cc',
'ipc_channel_unittest.cc',
'ipc_fuzzing_tests.cc',
+ 'ipc_message_attachment_set_posix_unittest.cc',
'ipc_message_unittest.cc',
'ipc_message_utils_unittest.cc',
'ipc_send_fds_test.cc',
@@ -132,6 +132,8 @@
'ipc_multiprocess_test.h',
'ipc_perftest_support.cc',
'ipc_perftest_support.h',
+ 'ipc_security_test_util.cc',
+ 'ipc_security_test_util.h',
'ipc_test_base.cc',
'ipc_test_base.h',
'ipc_test_channel_listener.cc',
diff --git a/chromium/ipc/ipc.gypi b/chromium/ipc/ipc.gypi
index 5f6875701ad..a10790ed103 100644
--- a/chromium/ipc/ipc.gypi
+++ b/chromium/ipc/ipc.gypi
@@ -11,8 +11,6 @@
# This part is shared between the targets defined below.
['ipc_target==1', {
'sources': [
- 'file_descriptor_set_posix.cc',
- 'file_descriptor_set_posix.h',
'ipc_channel.cc',
'ipc_channel.h',
'ipc_channel_factory.cc',
@@ -38,6 +36,10 @@
'ipc_logging.h',
'ipc_message.cc',
'ipc_message.h',
+ 'ipc_message_attachment.cc',
+ 'ipc_message_attachment.h',
+ 'ipc_message_attachment_set.cc',
+ 'ipc_message_attachment_set.h',
'ipc_message_macros.h',
'ipc_message_start.h',
'ipc_message_utils.cc',
@@ -45,6 +47,8 @@
'ipc_param_traits.h',
'ipc_platform_file.cc',
'ipc_platform_file.h',
+ 'ipc_platform_file_attachment_posix.cc',
+ 'ipc_platform_file_attachment_posix.h',
'ipc_sender.h',
'ipc_switches.cc',
'ipc_switches.h',
diff --git a/chromium/ipc/ipc_channel.cc b/chromium/ipc/ipc_channel.cc
index 4a4e40ddc1f..ac09c5ab1ef 100644
--- a/chromium/ipc/ipc_channel.cc
+++ b/chromium/ipc/ipc_channel.cc
@@ -28,8 +28,13 @@ std::string Channel::GenerateUniqueRandomChannelID() {
// the creator, an identifier for the child instance, and a strong random
// component. The strong random component prevents other processes from
// hijacking or squatting on predictable channel names.
-
+#if defined(OS_NACL_NONSFI)
+ // The seccomp sandbox disallows use of getpid(), so we provide a
+ // dummy PID.
+ int process_id = -1;
+#else
int process_id = base::GetCurrentProcId();
+#endif
return base::StringPrintf("%d.%u.%d",
process_id,
g_last_id.GetNext(),
diff --git a/chromium/ipc/ipc_channel.h b/chromium/ipc/ipc_channel.h
index 2fc52cb5875..65c678b530d 100644
--- a/chromium/ipc/ipc_channel.h
+++ b/chromium/ipc/ipc_channel.h
@@ -178,7 +178,11 @@ class IPC_EXPORT Channel : public Sender {
//
// |message| must be allocated using operator new. This object will be
// deleted once the contents of the Message have been sent.
- virtual bool Send(Message* message) override = 0;
+ bool Send(Message* message) override = 0;
+
+ // IsSendThreadSafe returns true iff it's safe to call |Send| from non-IO
+ // threads. This is constant for the lifetime of the |Channel|.
+ virtual bool IsSendThreadSafe() const;
// NaCl in Non-SFI mode runs on Linux directly, and the following functions
// compiled on Linux are also needed. Please see also comments in
diff --git a/chromium/ipc/ipc_channel_common.cc b/chromium/ipc/ipc_channel_common.cc
index d7347cc7a1b..23b85e2834d 100644
--- a/chromium/ipc/ipc_channel_common.cc
+++ b/chromium/ipc/ipc_channel_common.cc
@@ -43,5 +43,9 @@ scoped_ptr<Channel> Channel::CreateServer(
Channel::~Channel() {
}
+bool Channel::IsSendThreadSafe() const {
+ return false;
+}
+
} // namespace IPC
diff --git a/chromium/ipc/ipc_channel_nacl.cc b/chromium/ipc/ipc_channel_nacl.cc
index 783ee262060..f5b33cea41a 100644
--- a/chromium/ipc/ipc_channel_nacl.cc
+++ b/chromium/ipc/ipc_channel_nacl.cc
@@ -12,13 +12,14 @@
#include "base/bind.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/simple_thread.h"
-#include "ipc/file_descriptor_set_posix.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_logging.h"
+#include "ipc/ipc_message_attachment_set.h"
#include "native_client/src/public/imc_syscalls.h"
#include "native_client/src/public/imc_types.h"
@@ -37,7 +38,7 @@ bool ReadDataOnReaderThread(int pipe, MessageContents* contents) {
return false;
contents->data.resize(Channel::kReadBufferSize);
- contents->fds.resize(FileDescriptorSet::kMaxDescriptorsPerMessage);
+ contents->fds.resize(NACL_ABI_IMC_DESC_MAX);
NaClAbiNaClImcMsgIoVec iov = { &contents->data[0], contents->data.size() };
NaClAbiNaClImcMsgHdr msg = {
@@ -74,32 +75,32 @@ class ChannelNacl::ReaderThreadRunner
// above callbacks.
ReaderThreadRunner(
int pipe,
- base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback,
- base::Callback<void ()> failure_callback,
- scoped_refptr<base::MessageLoopProxy> main_message_loop);
+ base::Callback<void(scoped_ptr<MessageContents>)> data_read_callback,
+ base::Callback<void()> failure_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
// DelegateSimpleThread implementation. Reads data from the pipe in a loop
// until either we are told to quit or a read fails.
- virtual void Run() override;
+ void Run() override;
private:
int pipe_;
base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_;
base::Callback<void ()> failure_callback_;
- scoped_refptr<base::MessageLoopProxy> main_message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner);
};
ChannelNacl::ReaderThreadRunner::ReaderThreadRunner(
int pipe,
- base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback,
- base::Callback<void ()> failure_callback,
- scoped_refptr<base::MessageLoopProxy> main_message_loop)
+ base::Callback<void(scoped_ptr<MessageContents>)> data_read_callback,
+ base::Callback<void()> failure_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
: pipe_(pipe),
data_read_callback_(data_read_callback),
failure_callback_(failure_callback),
- main_message_loop_(main_message_loop) {
+ main_task_runner_(main_task_runner) {
}
void ChannelNacl::ReaderThreadRunner::Run() {
@@ -107,10 +108,11 @@ void ChannelNacl::ReaderThreadRunner::Run() {
scoped_ptr<MessageContents> msg_contents(new MessageContents);
bool success = ReadDataOnReaderThread(pipe_, msg_contents.get());
if (success) {
- main_message_loop_->PostTask(FROM_HERE,
+ main_task_runner_->PostTask(
+ FROM_HERE,
base::Bind(data_read_callback_, base::Passed(&msg_contents)));
} else {
- main_message_loop_->PostTask(FROM_HERE, failure_callback_);
+ main_task_runner_->PostTask(FROM_HERE, failure_callback_);
// Because the read failed, we know we're going to quit. Don't bother
// trying to read again.
return;
@@ -159,15 +161,13 @@ bool ChannelNacl::Connect() {
// where Channel::Send will be called, and the same thread that should receive
// messages). The constructor might be invoked on another thread (see
// ChannelProxy for an example of that). Therefore, we must wait until Connect
- // is called to decide which MessageLoopProxy to pass to ReaderThreadRunner.
- reader_thread_runner_.reset(
- new ReaderThreadRunner(
- pipe_,
- base::Bind(&ChannelNacl::DidRecvMsg,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&ChannelNacl::ReadDidFail,
- weak_ptr_factory_.GetWeakPtr()),
- base::MessageLoopProxy::current()));
+ // is called to decide which SingleThreadTaskRunner to pass to
+ // ReaderThreadRunner.
+ reader_thread_runner_.reset(new ReaderThreadRunner(
+ pipe_,
+ base::Bind(&ChannelNacl::DidRecvMsg, weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&ChannelNacl::ReadDidFail, weak_ptr_factory_.GetWeakPtr()),
+ base::ThreadTaskRunnerHandle::Get()));
reader_thread_.reset(
new base::DelegateSimpleThread(reader_thread_runner_.get(),
"ipc_channel_nacl reader thread"));
@@ -175,9 +175,9 @@ bool ChannelNacl::Connect() {
waiting_connect_ = false;
// If there were any messages queued before connection, send them.
ProcessOutgoingMessages();
- base::MessageLoopProxy::current()->PostTask(FROM_HERE,
- base::Bind(&ChannelNacl::CallOnChannelConnected,
- weak_ptr_factory_.GetWeakPtr()));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&ChannelNacl::CallOnChannelConnected,
+ weak_ptr_factory_.GetWeakPtr()));
return true;
}
@@ -200,6 +200,7 @@ void ChannelNacl::Close() {
}
bool ChannelNacl::Send(Message* message) {
+ DCHECK(!message->HasAttachments());
DVLOG(2) << "sending message @" << message << " on channel @" << this
<< " with type " << message->type();
scoped_ptr<Message> message_ptr(message);
@@ -275,10 +276,10 @@ bool ChannelNacl::ProcessOutgoingMessages() {
linked_ptr<Message> msg = output_queue_.front();
output_queue_.pop_front();
- int fds[FileDescriptorSet::kMaxDescriptorsPerMessage];
- const size_t num_fds = msg->file_descriptor_set()->size();
- DCHECK(num_fds <= FileDescriptorSet::kMaxDescriptorsPerMessage);
- msg->file_descriptor_set()->PeekDescriptors(fds);
+ int fds[MessageAttachmentSet::kMaxDescriptorsPerMessage];
+ const size_t num_fds = msg->attachment_set()->size();
+ DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage);
+ msg->attachment_set()->PeekDescriptors(fds);
NaClAbiNaClImcMsgIoVec iov = {
const_cast<void*>(msg->data()), msg->size()
@@ -298,7 +299,7 @@ bool ChannelNacl::ProcessOutgoingMessages() {
<< msg->size();
return false;
} else {
- msg->file_descriptor_set()->CommitAll();
+ msg->attachment_set()->CommitAll();
}
// Message sent OK!
@@ -352,8 +353,7 @@ bool ChannelNacl::WillDispatchInputMessage(Message* msg) {
// The shenaniganery below with &foo.front() requires input_fds_ to have
// contiguous underlying storage (such as a simple array or a std::vector).
// This is why the header warns not to make input_fds_ a deque<>.
- msg->file_descriptor_set()->AddDescriptorsToOwn(&input_fds_.front(),
- header_fds);
+ msg->attachment_set()->AddDescriptorsToOwn(&input_fds_.front(), header_fds);
input_fds_.clear();
return true;
}
diff --git a/chromium/ipc/ipc_channel_nacl.h b/chromium/ipc/ipc_channel_nacl.h
index 9c1e80fb10f..f0649b26022 100644
--- a/chromium/ipc/ipc_channel_nacl.h
+++ b/chromium/ipc/ipc_channel_nacl.h
@@ -38,14 +38,14 @@ class ChannelNacl : public Channel,
ChannelNacl(const IPC::ChannelHandle& channel_handle,
Mode mode,
Listener* listener);
- virtual ~ChannelNacl();
+ ~ChannelNacl() override;
// Channel implementation.
- virtual base::ProcessId GetPeerPID() const override;
- virtual base::ProcessId GetSelfPID() const override;
- virtual bool Connect() override;
- virtual void Close() override;
- virtual bool Send(Message* message) override;
+ base::ProcessId GetPeerPID() const override;
+ base::ProcessId GetSelfPID() const override;
+ bool Connect() override;
+ void Close() override;
+ bool Send(Message* message) override;
// Posted to the main thread by ReaderThreadRunner.
void DidRecvMsg(scoped_ptr<MessageContents> contents);
@@ -59,12 +59,12 @@ class ChannelNacl : public Channel,
void CallOnChannelConnected();
// ChannelReader implementation.
- virtual ReadState ReadData(char* buffer,
- int buffer_len,
- int* bytes_read) override;
- virtual bool WillDispatchInputMessage(Message* msg) override;
- virtual bool DidEmptyInputBuffers() override;
- virtual void HandleInternalMessage(const Message& msg) override;
+ ReadState ReadData(char* buffer,
+ int buffer_len,
+ int* bytes_read) override;
+ bool WillDispatchInputMessage(Message* msg) override;
+ bool DidEmptyInputBuffers() override;
+ void HandleInternalMessage(const Message& msg) override;
Mode mode_;
bool waiting_connect_;
diff --git a/chromium/ipc/ipc_channel_posix.cc b/chromium/ipc/ipc_channel_posix.cc
index 08529932250..aac7e795257 100644
--- a/chromium/ipc/ipc_channel_posix.cc
+++ b/chromium/ipc/ipc_channel_posix.cc
@@ -37,11 +37,12 @@
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
-#include "ipc/file_descriptor_set_posix.h"
#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_logging.h"
+#include "ipc/ipc_message_attachment_set.h"
#include "ipc/ipc_message_utils.h"
+#include "ipc/ipc_platform_file_attachment_posix.h"
#include "ipc/ipc_switches.h"
#include "ipc/unix_domain_socket_util.h"
@@ -189,6 +190,7 @@ ChannelPosix::ChannelPosix(const IPC::ChannelHandle& channel_handle,
waiting_connect_(true),
message_send_bytes_written_(0),
pipe_name_(channel_handle.name),
+ in_dtor_(false),
must_unlink_(false) {
memset(input_cmsg_buf_, 0, sizeof(input_cmsg_buf_));
if (!CreatePipe(channel_handle)) {
@@ -200,6 +202,7 @@ ChannelPosix::ChannelPosix(const IPC::ChannelHandle& channel_handle,
}
ChannelPosix::~ChannelPosix() {
+ in_dtor_ = true;
Close();
}
@@ -395,13 +398,13 @@ void ChannelPosix::CloseFileDescriptors(Message* msg) {
// descriptor. For more information, see:
// http://crbug.com/298276
std::vector<int> to_close;
- msg->file_descriptor_set()->ReleaseFDsToClose(&to_close);
+ msg->attachment_set()->ReleaseFDsToClose(&to_close);
for (size_t i = 0; i < to_close.size(); i++) {
fds_to_close_.insert(to_close[i]);
QueueCloseFDMessage(to_close[i], 2);
}
#else
- msg->file_descriptor_set()->CommitAll();
+ msg->attachment_set()->CommitAll();
#endif
}
@@ -428,20 +431,19 @@ bool ChannelPosix::ProcessOutgoingMessages() {
struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write};
msgh.msg_iov = &iov;
msgh.msg_iovlen = 1;
- char buf[CMSG_SPACE(
- sizeof(int) * FileDescriptorSet::kMaxDescriptorsPerMessage)];
+ char buf[CMSG_SPACE(sizeof(int) *
+ MessageAttachmentSet::kMaxDescriptorsPerMessage)];
ssize_t bytes_written = 1;
int fd_written = -1;
- if (message_send_bytes_written_ == 0 &&
- !msg->file_descriptor_set()->empty()) {
+ if (message_send_bytes_written_ == 0 && !msg->attachment_set()->empty()) {
// This is the first chunk of a message which has descriptors to send
struct cmsghdr *cmsg;
- const unsigned num_fds = msg->file_descriptor_set()->size();
+ const unsigned num_fds = msg->attachment_set()->size();
- DCHECK(num_fds <= FileDescriptorSet::kMaxDescriptorsPerMessage);
- if (msg->file_descriptor_set()->ContainsDirectoryDescriptor()) {
+ DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage);
+ if (msg->attachment_set()->ContainsDirectoryDescriptor()) {
LOG(FATAL) << "Panic: attempting to transport directory descriptor over"
" IPC. Aborting to maintain sandbox isolation.";
// If you have hit this then something tried to send a file descriptor
@@ -457,7 +459,7 @@ bool ChannelPosix::ProcessOutgoingMessages() {
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
- msg->file_descriptor_set()->PeekDescriptors(
+ msg->attachment_set()->PeekDescriptors(
reinterpret_cast<int*>(CMSG_DATA(cmsg)));
msgh.msg_controllen = cmsg->cmsg_len;
@@ -488,7 +490,7 @@ bool ChannelPosix::ProcessOutgoingMessages() {
fd_written = pipe_.get();
#if defined(IPC_USES_READWRITE)
if ((mode_ & MODE_CLIENT_FLAG) && IsHelloMessage(*msg)) {
- DCHECK_EQ(msg->file_descriptor_set()->size(), 1U);
+ DCHECK_EQ(msg->attachment_set()->size(), 1U);
}
if (!msgh.msg_controllen) {
bytes_written =
@@ -554,6 +556,7 @@ bool ChannelPosix::ProcessOutgoingMessages() {
}
bool ChannelPosix::Send(Message* message) {
+ DCHECK(!message->HasMojoHandles());
DVLOG(2) << "sending message @" << message << " on channel @" << this
<< " with type " << message->type()
<< " (" << output_queue_.size() << " in queue)";
@@ -612,7 +615,7 @@ void ChannelPosix::ResetToAcceptingConnectionState() {
// Unregister libevent for the unix domain socket and close it.
read_watcher_.StopWatchingFileDescriptor();
write_watcher_.StopWatchingFileDescriptor();
- pipe_.reset();
+ ResetSafely(&pipe_);
#if defined(IPC_USES_READWRITE)
fd_pipe_.reset();
remote_fd_pipe_.reset();
@@ -771,14 +774,20 @@ void ChannelPosix::ClosePipeOnError() {
}
int ChannelPosix::GetHelloMessageProcId() const {
+#if defined(OS_NACL_NONSFI)
+ // In nacl_helper_nonsfi, getpid() invoked by GetCurrentProcId() is not
+ // allowed and would cause a SIGSYS crash because of the seccomp sandbox.
+ return -1;
+#else
int pid = base::GetCurrentProcId();
#if defined(OS_LINUX)
// Our process may be in a sandbox with a separate PID namespace.
if (global_pid_) {
pid = global_pid_;
}
-#endif
+#endif // defined(OS_LINUX)
return pid;
+#endif // defined(OS_NACL_NONSFI)
}
void ChannelPosix::QueueHelloMessage() {
@@ -792,10 +801,11 @@ void ChannelPosix::QueueHelloMessage() {
#if defined(IPC_USES_READWRITE)
scoped_ptr<Message> hello;
if (remote_fd_pipe_.is_valid()) {
- if (!msg->WriteBorrowingFile(remote_fd_pipe_.get())) {
+ if (!msg->WriteAttachment(
+ new internal::PlatformFileAttachment(remote_fd_pipe_.get()))) {
NOTREACHED() << "Unable to pickle hello message file descriptors";
}
- DCHECK_EQ(msg->file_descriptor_set()->size(), 1U);
+ DCHECK_EQ(msg->attachment_set()->size(), 1U);
}
#endif // IPC_USES_READWRITE
output_queue_.push(msg.release());
@@ -903,7 +913,7 @@ bool ChannelPosix::WillDispatchInputMessage(Message* msg) {
error = "Message needs unreceived descriptors";
}
- if (header_fds > FileDescriptorSet::kMaxDescriptorsPerMessage)
+ if (header_fds > MessageAttachmentSet::kMaxDescriptorsPerMessage)
error = "Message requires an excessive number of descriptors";
if (error) {
@@ -919,8 +929,7 @@ bool ChannelPosix::WillDispatchInputMessage(Message* msg) {
// The shenaniganery below with &foo.front() requires input_fds_ to have
// contiguous underlying storage (such as a simple array or a std::vector).
// This is why the header warns not to make input_fds_ a deque<>.
- msg->file_descriptor_set()->AddDescriptorsToOwn(&input_fds_.front(),
- header_fds);
+ msg->attachment_set()->AddDescriptorsToOwn(&input_fds_.front(), header_fds);
input_fds_.erase(input_fds_.begin(), input_fds_.begin() + header_fds);
return true;
}
@@ -1005,7 +1014,7 @@ void ChannelPosix::HandleInternalMessage(const Message& msg) {
case Channel::HELLO_MESSAGE_TYPE:
int pid;
- if (!msg.ReadInt(&iter, &pid))
+ if (!iter.ReadInt(&pid))
NOTREACHED();
#if defined(IPC_USES_READWRITE)
@@ -1013,12 +1022,12 @@ void ChannelPosix::HandleInternalMessage(const Message& msg) {
// With IPC_USES_READWRITE, the Hello message from the client to the
// server also contains the fd_pipe_, which will be used for all
// subsequent file descriptor passing.
- DCHECK_EQ(msg.file_descriptor_set()->size(), 1U);
- base::ScopedFD descriptor;
- if (!msg.ReadFile(&iter, &descriptor)) {
+ DCHECK_EQ(msg.attachment_set()->size(), 1U);
+ scoped_refptr<MessageAttachment> attachment;
+ if (!msg.ReadAttachment(&iter, &attachment)) {
NOTREACHED();
}
- fd_pipe_.reset(descriptor.release());
+ fd_pipe_.reset(attachment->TakePlatformFile());
}
#endif // IPC_USES_READWRITE
peer_pid_ = pid;
@@ -1028,9 +1037,9 @@ void ChannelPosix::HandleInternalMessage(const Message& msg) {
#if defined(OS_MACOSX)
case Channel::CLOSE_FD_MESSAGE_TYPE:
int fd, hops;
- if (!msg.ReadInt(&iter, &hops))
+ if (!iter.ReadInt(&hops))
NOTREACHED();
- if (!msg.ReadInt(&iter, &fd))
+ if (!iter.ReadInt(&fd))
NOTREACHED();
if (hops == 0) {
if (fds_to_close_.erase(fd) > 0) {
@@ -1080,6 +1089,25 @@ base::ProcessId ChannelPosix::GetSelfPID() const {
return GetHelloMessageProcId();
}
+void ChannelPosix::ResetSafely(base::ScopedFD* fd) {
+ if (!in_dtor_) {
+ fd->reset();
+ return;
+ }
+
+ // crbug.com/449233
+ // The CL [1] tightened the error check for closing FDs, but it turned
+ // out that there are existing cases that hit the newly added check.
+ // ResetSafely() is the workaround for that crash, turning it from
+ // from PCHECK() to DPCHECK() so that it doesn't crash in production.
+ // [1] https://crrev.com/ce44fef5fd60dd2be5c587d4b084bdcd36adcee4
+ int fd_to_close = fd->release();
+ if (-1 != fd_to_close) {
+ int rv = IGNORE_EINTR(close(fd_to_close));
+ DPCHECK(0 == rv);
+ }
+}
+
//------------------------------------------------------------------------------
// Channel's methods
diff --git a/chromium/ipc/ipc_channel_posix.h b/chromium/ipc/ipc_channel_posix.h
index 1cb76102c39..a65283d3bea 100644
--- a/chromium/ipc/ipc_channel_posix.h
+++ b/chromium/ipc/ipc_channel_posix.h
@@ -17,8 +17,8 @@
#include "base/files/scoped_file.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process.h"
-#include "ipc/file_descriptor_set_posix.h"
#include "ipc/ipc_channel_reader.h"
+#include "ipc/ipc_message_attachment_set.h"
#if !defined(OS_MACOSX)
// On Linux, the seccomp sandbox makes it very expensive to call
@@ -178,7 +178,7 @@ class IPC_EXPORT ChannelPosix : public Channel,
// message has no payload and a full complement of descriptors.
static const size_t kMaxReadFDs =
(Channel::kReadBufferSize / sizeof(IPC::Message::Header)) *
- FileDescriptorSet::kMaxDescriptorsPerMessage;
+ MessageAttachmentSet::kMaxDescriptorsPerMessage;
// Buffer size for file descriptors used for recvmsg. On Mac the CMSG macros
// don't seem to be constant so we have to pick a "large enough" value.
@@ -202,6 +202,10 @@ class IPC_EXPORT ChannelPosix : public Channel,
// implementation!
std::vector<int> input_fds_;
+
+ void ResetSafely(base::ScopedFD* fd);
+ bool in_dtor_;
+
#if defined(OS_MACOSX)
// On OSX, sent FDs must not be closed until we get an ack.
// Keep track of sent FDs here to make sure the remote is not
diff --git a/chromium/ipc/ipc_channel_posix_unittest.cc b/chromium/ipc/ipc_channel_posix_unittest.cc
index 786623b8062..aa545402f4b 100644
--- a/chromium/ipc/ipc_channel_posix_unittest.cc
+++ b/chromium/ipc/ipc_channel_posix_unittest.cc
@@ -14,11 +14,12 @@
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "base/location.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
-#include "base/process/kill.h"
+#include "base/process/process.h"
+#include "base/single_thread_task_runner.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
#include "ipc/ipc_listener.h"
@@ -88,7 +89,7 @@ class IPCChannelPosixTestListener : public IPC::Listener {
loop->QuitNow();
} else {
// Die as soon as Run is called.
- loop->PostTask(FROM_HERE, loop->QuitClosure());
+ loop->task_runner()->PostTask(FROM_HERE, loop->QuitClosure());
}
}
@@ -109,21 +110,17 @@ class IPCChannelPosixTest : public base::MultiProcessTest {
static const std::string GetChannelDirName();
protected:
- virtual void SetUp();
- virtual void TearDown();
+ void SetUp() override;
+ void TearDown() override;
private:
scoped_ptr<base::MessageLoopForIO> message_loop_;
};
const std::string IPCChannelPosixTest::GetChannelDirName() {
-#if defined(OS_ANDROID)
base::FilePath tmp_dir;
- PathService::Get(base::DIR_CACHE, &tmp_dir);
+ PathService::Get(base::DIR_TEMP, &tmp_dir);
return tmp_dir.value();
-#else
- return "/var/tmp";
-#endif
}
const std::string IPCChannelPosixTest::GetConnectionSocketName() {
@@ -192,7 +189,7 @@ void IPCChannelPosixTest::SpinRunLoop(base::TimeDelta delay) {
// in the case of a bad test. Usually, the run loop will quit sooner than
// that because all tests use a IPCChannelPosixTestListener which quits the
// current run loop on any channel activity.
- loop->PostDelayedTask(FROM_HERE, loop->QuitClosure(), delay);
+ loop->task_runner()->PostDelayedTask(FROM_HERE, loop->QuitClosure(), delay);
loop->Run();
}
@@ -211,6 +208,7 @@ TEST_F(IPCChannelPosixTest, BasicListen) {
ASSERT_FALSE(channel->HasAcceptedConnection());
channel->ResetToAcceptingConnectionState();
ASSERT_FALSE(channel->HasAcceptedConnection());
+ unlink(handle.name.c_str());
}
TEST_F(IPCChannelPosixTest, BasicConnected) {
@@ -293,8 +291,8 @@ TEST_F(IPCChannelPosixTest, AdvancedConnected) {
ASSERT_TRUE(channel->AcceptsConnections());
ASSERT_FALSE(channel->HasAcceptedConnection());
- base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
- ASSERT_TRUE(handle);
+ base::Process process = SpawnChild("IPCChannelPosixTestConnectionProc");
+ ASSERT_TRUE(process.IsValid());
SpinRunLoop(TestTimeouts::action_max_timeout());
ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
ASSERT_TRUE(channel->HasAcceptedConnection());
@@ -304,10 +302,11 @@ TEST_F(IPCChannelPosixTest, AdvancedConnected) {
channel->Send(message);
SpinRunLoop(TestTimeouts::action_timeout());
int exit_code = 0;
- EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
EXPECT_EQ(0, exit_code);
ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
ASSERT_FALSE(channel->HasAcceptedConnection());
+ unlink(chan_handle.name.c_str());
}
TEST_F(IPCChannelPosixTest, ResetState) {
@@ -323,16 +322,16 @@ TEST_F(IPCChannelPosixTest, ResetState) {
ASSERT_TRUE(channel->AcceptsConnections());
ASSERT_FALSE(channel->HasAcceptedConnection());
- base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
- ASSERT_TRUE(handle);
+ base::Process process = SpawnChild("IPCChannelPosixTestConnectionProc");
+ ASSERT_TRUE(process.IsValid());
SpinRunLoop(TestTimeouts::action_max_timeout());
ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
ASSERT_TRUE(channel->HasAcceptedConnection());
channel->ResetToAcceptingConnectionState();
ASSERT_FALSE(channel->HasAcceptedConnection());
- base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc");
- ASSERT_TRUE(handle2);
+ base::Process process2 = SpawnChild("IPCChannelPosixTestConnectionProc");
+ ASSERT_TRUE(process2.IsValid());
SpinRunLoop(TestTimeouts::action_max_timeout());
ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
ASSERT_TRUE(channel->HasAcceptedConnection());
@@ -341,12 +340,13 @@ TEST_F(IPCChannelPosixTest, ResetState) {
IPC::Message::PRIORITY_NORMAL);
channel->Send(message);
SpinRunLoop(TestTimeouts::action_timeout());
- EXPECT_TRUE(base::KillProcess(handle, 0, false));
+ EXPECT_TRUE(process.Terminate(0, false));
int exit_code = 0;
- EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
+ EXPECT_TRUE(process2.WaitForExit(&exit_code));
EXPECT_EQ(0, exit_code);
ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
ASSERT_FALSE(channel->HasAcceptedConnection());
+ unlink(chan_handle.name.c_str());
}
TEST_F(IPCChannelPosixTest, BadChannelName) {
@@ -383,16 +383,16 @@ TEST_F(IPCChannelPosixTest, MultiConnection) {
ASSERT_TRUE(channel->AcceptsConnections());
ASSERT_FALSE(channel->HasAcceptedConnection());
- base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
- ASSERT_TRUE(handle);
+ base::Process process = SpawnChild("IPCChannelPosixTestConnectionProc");
+ ASSERT_TRUE(process.IsValid());
SpinRunLoop(TestTimeouts::action_max_timeout());
ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
ASSERT_TRUE(channel->HasAcceptedConnection());
- base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc");
- ASSERT_TRUE(handle2);
+ base::Process process2 = SpawnChild("IPCChannelPosixFailConnectionProc");
+ ASSERT_TRUE(process2.IsValid());
SpinRunLoop(TestTimeouts::action_max_timeout());
int exit_code = 0;
- EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
+ EXPECT_TRUE(process2.WaitForExit(&exit_code));
EXPECT_EQ(exit_code, 0);
ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status());
ASSERT_TRUE(channel->HasAcceptedConnection());
@@ -401,10 +401,11 @@ TEST_F(IPCChannelPosixTest, MultiConnection) {
IPC::Message::PRIORITY_NORMAL);
channel->Send(message);
SpinRunLoop(TestTimeouts::action_timeout());
- EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
EXPECT_EQ(exit_code, 0);
ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
ASSERT_FALSE(channel->HasAcceptedConnection());
+ unlink(chan_handle.name.c_str());
}
TEST_F(IPCChannelPosixTest, DoubleServer) {
@@ -443,6 +444,7 @@ TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) {
channel->Close();
ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
connection_socket_name));
+ unlink(chan_handle.name.c_str());
}
// A long running process that connects to us
diff --git a/chromium/ipc/ipc_channel_proxy.cc b/chromium/ipc/ipc_channel_proxy.cc
index 64fab8fca56..57676189b8d 100644
--- a/chromium/ipc/ipc_channel_proxy.cc
+++ b/chromium/ipc/ipc_channel_proxy.cc
@@ -9,6 +9,7 @@
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "ipc/ipc_channel_factory.h"
@@ -29,6 +30,7 @@ ChannelProxy::Context::Context(
listener_(listener),
ipc_task_runner_(ipc_task_runner),
channel_connected_called_(false),
+ channel_send_thread_safe_(false),
message_filter_router_(new MessageFilterRouter()),
peer_pid_(base::kNullProcessId) {
DCHECK(ipc_task_runner_.get());
@@ -50,10 +52,20 @@ void ChannelProxy::Context::ClearIPCTaskRunner() {
ipc_task_runner_ = NULL;
}
+void ChannelProxy::Context::SetListenerTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ DCHECK(ipc_task_runner_.get() != task_runner.get());
+ DCHECK(listener_task_runner_->BelongsToCurrentThread());
+ DCHECK(task_runner->BelongsToCurrentThread());
+ listener_task_runner_ = task_runner;
+}
+
void ChannelProxy::Context::CreateChannel(scoped_ptr<ChannelFactory> factory) {
+ base::AutoLock l(channel_lifetime_lock_);
DCHECK(!channel_);
channel_id_ = factory->GetName();
channel_ = factory->BuildChannel(this);
+ channel_send_thread_safe_ = channel_->IsSendThreadSafe();
}
bool ChannelProxy::Context::TryFilters(const Message& message) {
@@ -138,6 +150,10 @@ void ChannelProxy::Context::OnChannelOpened() {
// Called on the IPC::Channel thread
void ChannelProxy::Context::OnChannelClosed() {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "477117 ChannelProxy::Context::OnChannelClosed"));
// It's okay for IPC::ChannelProxy::Close to be called more than once, which
// would result in this branch being taken.
if (!channel_)
@@ -155,7 +171,7 @@ void ChannelProxy::Context::OnChannelClosed() {
// access it any more.
pending_filters_.clear();
- channel_.reset();
+ ClearChannel();
// Balance with the reference taken during startup. This may result in
// self-destruction.
@@ -168,6 +184,10 @@ void ChannelProxy::Context::Clear() {
// Called on the IPC::Channel thread
void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) {
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "477117 ChannelProxy::Context::OnSendMessage"));
if (!channel_) {
OnChannelClosed();
return;
@@ -244,7 +264,7 @@ void ChannelProxy::Context::AddFilter(MessageFilter* filter) {
// Called on the listener's thread
void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
-#ifdef IPC_MESSAGE_LOG_ENABLED
+#if defined(IPC_MESSAGE_LOG_ENABLED)
Logging* logger = Logging::GetInstance();
std::string name;
logger->GetMessageText(message.type(), &name, &message, NULL);
@@ -303,6 +323,31 @@ void ChannelProxy::Context::OnDispatchBadMessage(const Message& message) {
listener_->OnBadMessageReceived(message);
}
+void ChannelProxy::Context::ClearChannel() {
+ base::AutoLock l(channel_lifetime_lock_);
+ channel_.reset();
+}
+
+void ChannelProxy::Context::SendFromThisThread(Message* message) {
+ base::AutoLock l(channel_lifetime_lock_);
+ if (!channel_)
+ return;
+ DCHECK(channel_->IsSendThreadSafe());
+ channel_->Send(message);
+}
+
+void ChannelProxy::Context::Send(Message* message) {
+ if (channel_send_thread_safe_) {
+ SendFromThisThread(message);
+ return;
+ }
+
+ ipc_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ChannelProxy::Context::OnSendMessage, this,
+ base::Passed(scoped_ptr<Message>(message))));
+}
+
+
//-----------------------------------------------------------------------------
// static
@@ -329,12 +374,18 @@ scoped_ptr<ChannelProxy> ChannelProxy::Create(
ChannelProxy::ChannelProxy(Context* context)
: context_(context),
did_init_(false) {
+#if defined(ENABLE_IPC_FUZZER)
+ outgoing_message_filter_ = NULL;
+#endif
}
ChannelProxy::ChannelProxy(
Listener* listener,
const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner)
: context_(new Context(listener, ipc_task_runner)), did_init_(false) {
+#if defined(ENABLE_IPC_FUZZER)
+ outgoing_message_filter_ = NULL;
+#endif
}
ChannelProxy::~ChannelProxy() {
@@ -403,14 +454,19 @@ bool ChannelProxy::Send(Message* message) {
// TODO(alexeypa): add DCHECK(CalledOnValidThread()) here. Currently there are
// tests that call Send() from a wrong thread. See http://crbug.com/163523.
+#ifdef ENABLE_IPC_FUZZER
+ // In IPC fuzzing builds, it is possible to define a filter to apply to
+ // outgoing messages. It will either rewrite the message and return a new
+ // one, freeing the original, or return the message unchanged.
+ if (outgoing_message_filter())
+ message = outgoing_message_filter()->Rewrite(message);
+#endif
+
#ifdef IPC_MESSAGE_LOG_ENABLED
Logging::GetInstance()->OnSendMessage(message, context_->channel_id());
#endif
- context_->ipc_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&ChannelProxy::Context::OnSendMessage,
- context_, base::Passed(scoped_ptr<Message>(message))));
+ context_->Send(message);
return true;
}
@@ -428,6 +484,13 @@ void ChannelProxy::RemoveFilter(MessageFilter* filter) {
make_scoped_refptr(filter)));
}
+void ChannelProxy::SetListenerTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ DCHECK(CalledOnValidThread());
+
+ context()->SetListenerTaskRunner(task_runner);
+}
+
void ChannelProxy::ClearIPCTaskRunner() {
DCHECK(CalledOnValidThread());
diff --git a/chromium/ipc/ipc_channel_proxy.h b/chromium/ipc/ipc_channel_proxy.h
index dda5fa5f41c..5d38006b5d5 100644
--- a/chromium/ipc/ipc_channel_proxy.h
+++ b/chromium/ipc/ipc_channel_proxy.h
@@ -55,8 +55,25 @@ class SendCallbackHelper;
// The consumer of IPC::ChannelProxy is responsible for allocating the Thread
// instance where the IPC::Channel will be created and operated.
//
+// Thread-safe send
+//
+// If a particular |Channel| implementation has a thread-safe |Send()| operation
+// then ChannelProxy skips the inter-thread hop and calls |Send()| directly. In
+// this case the |channel_| variable is touched by multiple threads so
+// |channel_lifetime_lock_| is used to protect it. The locking overhead is only
+// paid if the underlying channel supports thread-safe |Send|.
+//
class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
public:
+#if defined(ENABLE_IPC_FUZZER)
+ // Interface for a filter to be imposed on outgoing messages which can
+ // re-write the message. Used for testing.
+ class OutgoingMessageFilter {
+ public:
+ virtual Message* Rewrite(Message* message) = 0;
+ };
+#endif
+
// Initializes a channel proxy. The channel_handle and mode parameters are
// passed directly to the underlying IPC::Channel. The listener is called on
// the thread that creates the ChannelProxy. The filter's OnMessageReceived
@@ -112,6 +129,18 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
void AddFilter(MessageFilter* filter);
void RemoveFilter(MessageFilter* filter);
+#if defined(ENABLE_IPC_FUZZER)
+ void set_outgoing_message_filter(OutgoingMessageFilter* filter) {
+ outgoing_message_filter_ = filter;
+ }
+#endif
+
+ // Set the task runner on which dispatched messages are posted. Both the new
+ // task runner and the existing task runner must run on the same thread, and
+ // must belong to the calling thread.
+ void SetListenerTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner);
+
// Called to clear the pointer to the IPC task runner when it's going away.
void ClearIPCTaskRunner();
@@ -142,6 +171,8 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
Context(Listener* listener,
const scoped_refptr<base::SingleThreadTaskRunner>& ipc_thread);
void ClearIPCTaskRunner();
+ void SetListenerTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner);
base::SingleThreadTaskRunner* ipc_task_runner() const {
return ipc_task_runner_.get();
}
@@ -150,6 +181,9 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// Dispatches a message on the listener thread.
void OnDispatchMessage(const Message& message);
+ // Sends |message| from appropriate thread.
+ void Send(Message* message);
+
protected:
friend class base::RefCountedThreadSafe<Context>;
~Context() override;
@@ -177,7 +211,7 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
private:
friend class ChannelProxy;
- friend class SendCallbackHelper;
+ friend class IpcSecurityTestUtil;
// Create the Channel
void CreateChannel(scoped_ptr<ChannelFactory> factory);
@@ -193,6 +227,9 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
void OnDispatchError();
void OnDispatchBadMessage(const Message& message);
+ void SendFromThisThread(Message* message);
+ void ClearChannel();
+
scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
Listener* listener_;
@@ -203,10 +240,18 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// Note, channel_ may be set on the Listener thread or the IPC thread.
// But once it has been set, it must only be read or cleared on the IPC
// thread.
+ // One exception is the thread-safe send. See the class comment.
scoped_ptr<Channel> channel_;
std::string channel_id_;
bool channel_connected_called_;
+ // Lock for |channel_| value. This is only relevant in the context of
+ // thread-safe send.
+ base::Lock channel_lifetime_lock_;
+ // Indicates the thread-safe send availability. This is constant once
+ // |channel_| is set.
+ bool channel_send_thread_safe_;
+
// Routes a given message to a proper subset of |filters_|, depending
// on which message classes a filter might support.
scoped_ptr<MessageFilterRouter> message_filter_router_;
@@ -224,8 +269,14 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
Context* context() { return context_.get(); }
+#if defined(ENABLE_IPC_FUZZER)
+ OutgoingMessageFilter* outgoing_message_filter() const {
+ return outgoing_message_filter_;
+ }
+#endif
+
private:
- friend class SendCallbackHelper;
+ friend class IpcSecurityTestUtil;
// By maintaining this indirection (ref-counted) to our internal state, we
// can safely be destroyed while the background thread continues to do stuff
@@ -234,6 +285,10 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// Whether the channel has been initialized.
bool did_init_;
+
+#if defined(ENABLE_IPC_FUZZER)
+ OutgoingMessageFilter* outgoing_message_filter_;
+#endif
};
} // namespace IPC
diff --git a/chromium/ipc/ipc_channel_proxy_unittest.cc b/chromium/ipc/ipc_channel_proxy_unittest.cc
index 848367ec782..4144a8adba1 100644
--- a/chromium/ipc/ipc_channel_proxy_unittest.cc
+++ b/chromium/ipc/ipc_channel_proxy_unittest.cc
@@ -4,7 +4,6 @@
#include "build/build_config.h"
-#include "base/message_loop/message_loop.h"
#include "base/pickle.h"
#include "base/threading/thread.h"
#include "ipc/ipc_message.h"
@@ -47,7 +46,6 @@ namespace {
class QuitListener : public IPC::Listener {
public:
QuitListener() : bad_message_received_(false) {}
- ~QuitListener() override {}
bool OnMessageReceived(const IPC::Message& message) override {
IPC_BEGIN_MESSAGE_MAP(QuitListener, message)
@@ -76,7 +74,6 @@ class QuitListener : public IPC::Listener {
class ChannelReflectorListener : public IPC::Listener {
public:
ChannelReflectorListener() : channel_(NULL) {}
- ~ChannelReflectorListener() override {}
void Init(IPC::Channel* channel) {
DCHECK(!channel_);
@@ -232,9 +229,9 @@ class MessageCountFilter : public IPC::MessageFilter {
class IPCChannelProxyTest : public IPCTestBase {
public:
IPCChannelProxyTest() {}
- virtual ~IPCChannelProxyTest() {}
+ ~IPCChannelProxyTest() override {}
- virtual void SetUp() override {
+ void SetUp() override {
IPCTestBase::SetUp();
Init("ChannelProxyClient");
@@ -245,12 +242,12 @@ class IPCChannelProxyTest : public IPCTestBase {
thread_->StartWithOptions(options);
listener_.reset(new QuitListener());
- CreateChannelProxy(listener_.get(), thread_->message_loop_proxy().get());
+ CreateChannelProxy(listener_.get(), thread_->task_runner().get());
ASSERT_TRUE(StartClient());
}
- virtual void TearDown() {
+ void TearDown() override {
DestroyChannelProxy();
thread_.reset();
listener_.reset();
@@ -380,10 +377,7 @@ TEST_F(IPCChannelProxyTest, BadMessageOnIPCThread) {
class IPCChannelBadMessageTest : public IPCTestBase {
public:
- IPCChannelBadMessageTest() {}
- virtual ~IPCChannelBadMessageTest() {}
-
- virtual void SetUp() override {
+ void SetUp() override {
IPCTestBase::SetUp();
Init("ChannelProxyClient");
@@ -395,7 +389,7 @@ class IPCChannelBadMessageTest : public IPCTestBase {
ASSERT_TRUE(StartClient());
}
- virtual void TearDown() {
+ void TearDown() override {
listener_.reset();
IPCTestBase::TearDown();
}
diff --git a/chromium/ipc/ipc_channel_unittest.cc b/chromium/ipc/ipc_channel_unittest.cc
index dd31e9e9c47..b6a02262613 100644
--- a/chromium/ipc/ipc_channel_unittest.cc
+++ b/chromium/ipc/ipc_channel_unittest.cc
@@ -10,8 +10,9 @@
#include <string>
-#include "base/message_loop/message_loop.h"
#include "base/pickle.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_test_base.h"
@@ -26,32 +27,32 @@ class IPCChannelTest : public IPCTestBase {
TEST_F(IPCChannelTest, BasicMessageTest) {
int v1 = 10;
std::string v2("foobar");
- std::wstring v3(L"hello world");
+ base::string16 v3(base::ASCIIToUTF16("hello world"));
IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
EXPECT_TRUE(m.WriteInt(v1));
EXPECT_TRUE(m.WriteString(v2));
- EXPECT_TRUE(m.WriteWString(v3));
+ EXPECT_TRUE(m.WriteString16(v3));
PickleIterator iter(m);
int vi;
std::string vs;
- std::wstring vw;
+ base::string16 vs16;
- EXPECT_TRUE(m.ReadInt(&iter, &vi));
+ EXPECT_TRUE(iter.ReadInt(&vi));
EXPECT_EQ(v1, vi);
- EXPECT_TRUE(m.ReadString(&iter, &vs));
+ EXPECT_TRUE(iter.ReadString(&vs));
EXPECT_EQ(v2, vs);
- EXPECT_TRUE(m.ReadWString(&iter, &vw));
- EXPECT_EQ(v3, vw);
+ EXPECT_TRUE(iter.ReadString16(&vs16));
+ EXPECT_EQ(v3, vs16);
// should fail
- EXPECT_FALSE(m.ReadInt(&iter, &vi));
- EXPECT_FALSE(m.ReadString(&iter, &vs));
- EXPECT_FALSE(m.ReadWString(&iter, &vw));
+ EXPECT_FALSE(iter.ReadInt(&vi));
+ EXPECT_FALSE(iter.ReadString(&vs));
+ EXPECT_FALSE(iter.ReadString16(&vs16));
}
TEST_F(IPCChannelTest, ChannelTest) {
@@ -126,7 +127,7 @@ TEST_F(IPCChannelTest, ChannelProxyTest) {
// Set up IPC channel proxy.
IPC::TestChannelListener listener;
- CreateChannelProxy(&listener, thread.message_loop_proxy().get());
+ CreateChannelProxy(&listener, thread.task_runner().get());
listener.Init(sender());
ASSERT_TRUE(StartClient());
diff --git a/chromium/ipc/ipc_channel_win.cc b/chromium/ipc/ipc_channel_win.cc
index db8c96116e3..27043730695 100644
--- a/chromium/ipc/ipc_channel_win.cc
+++ b/chromium/ipc/ipc_channel_win.cc
@@ -21,27 +21,6 @@
#include "ipc/ipc_logging.h"
#include "ipc/ipc_message_utils.h"
-namespace {
-
-enum DebugFlags {
- INIT_DONE = 1 << 0,
- CALLED_CONNECT = 1 << 1,
- PENDING_CONNECT = 1 << 2,
- CONNECT_COMPLETED = 1 << 3,
- PIPE_CONNECTED = 1 << 4,
- WRITE_MSG = 1 << 5,
- READ_MSG = 1 << 6,
- WRITE_COMPLETED = 1 << 7,
- READ_COMPLETED = 1 << 8,
- CLOSED = 1 << 9,
- WAIT_FOR_READ = 1 << 10,
- WAIT_FOR_WRITE = 1 << 11,
- WAIT_FOR_READ_COMPLETE = 1 << 12,
- WAIT_FOR_WRITE_COMPLETE = 1 << 13
-};
-
-} // namespace
-
namespace IPC {
ChannelWin::State::State(ChannelWin* channel) : is_pending(false) {
@@ -50,8 +29,9 @@ ChannelWin::State::State(ChannelWin* channel) : is_pending(false) {
}
ChannelWin::State::~State() {
- COMPILE_ASSERT(!offsetof(ChannelWin::State, context),
- starts_with_io_context);
+ static_assert(offsetof(ChannelWin::State, context) == 0,
+ "ChannelWin::State should have context as its first data"
+ "member.");
}
ChannelWin::ChannelWin(const IPC::ChannelHandle &channel_handle,
@@ -63,11 +43,6 @@ ChannelWin::ChannelWin(const IPC::ChannelHandle &channel_handle,
waiting_connect_(mode & MODE_SERVER_FLAG),
processing_incoming_(false),
validate_client_(false),
- writing_(false),
- debug_flags_(0),
- write_error_(0),
- last_write_error_(0),
- write_size_(0),
client_secret_(0),
weak_factory_(this) {
CreatePipe(channel_handle, mode);
@@ -78,10 +53,8 @@ ChannelWin::~ChannelWin() {
}
void ChannelWin::Close() {
- if (thread_check_.get()) {
+ if (thread_check_.get())
DCHECK(thread_check_->CalledOnValidThread());
- }
- debug_flags_ |= CLOSED;
if (input_state_.is_pending || output_state_.is_pending)
CancelIo(pipe_.Get());
@@ -91,12 +64,6 @@ void ChannelWin::Close() {
if (pipe_.IsValid())
pipe_.Close();
- if (input_state_.is_pending)
- debug_flags_ |= WAIT_FOR_READ;
-
- if (output_state_.is_pending)
- debug_flags_ |= WAIT_FOR_WRITE;
-
// Make sure all IO has completed.
base::Time start = base::Time::Now();
while (input_state_.is_pending || output_state_.is_pending) {
@@ -111,6 +78,7 @@ void ChannelWin::Close() {
}
bool ChannelWin::Send(Message* message) {
+ DCHECK(!message->HasAttachments());
DCHECK(thread_check_->CalledOnValidThread());
DVLOG(2) << "sending message @" << message << " on channel @" << this
<< " with type " << message->type()
@@ -158,7 +126,6 @@ ChannelWin::ReadState ChannelWin::ReadData(
if (!pipe_.IsValid())
return READ_FAILED;
- debug_flags_ |= READ_MSG;
DWORD bytes_read = 0;
BOOL ok = ReadFile(pipe_.Get(), buffer, buffer_len,
&bytes_read, &input_state_.context.overlapped);
@@ -297,7 +264,7 @@ bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle,
0,
NULL,
OPEN_EXISTING,
- SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
+ SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS |
FILE_FLAG_OVERLAPPED,
NULL));
} else {
@@ -325,8 +292,6 @@ bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle,
return false;
}
- debug_flags_ |= INIT_DONE;
-
output_queue_.push(m.release());
return true;
}
@@ -374,8 +339,6 @@ bool ChannelWin::ProcessConnection() {
return false;
BOOL ok = ConnectNamedPipe(pipe_.Get(), &input_state_.context.overlapped);
- debug_flags_ |= CALLED_CONNECT;
-
DWORD err = GetLastError();
if (ok) {
// Uhm, the API documentation says that this function should never
@@ -387,10 +350,8 @@ bool ChannelWin::ProcessConnection() {
switch (err) {
case ERROR_IO_PENDING:
input_state_.is_pending = true;
- debug_flags_ |= PENDING_CONNECT;
break;
case ERROR_PIPE_CONNECTED:
- debug_flags_ |= PIPE_CONNECTED;
waiting_connect_ = false;
break;
case ERROR_NO_DATA:
@@ -435,19 +396,14 @@ bool ChannelWin::ProcessOutgoingMessages(
// Write to pipe...
Message* m = output_queue_.front();
DCHECK(m->size() <= INT_MAX);
- debug_flags_ |= WRITE_MSG;
- CHECK(!writing_);
- writing_ = true;
- write_size_ = static_cast<uint32>(m->size());
- write_error_ = 0;
BOOL ok = WriteFile(pipe_.Get(),
m->data(),
- write_size_,
+ static_cast<uint32>(m->size()),
NULL,
&output_state_.context.overlapped);
if (!ok) {
- write_error_ = GetLastError();
- if (write_error_ == ERROR_IO_PENDING) {
+ DWORD write_error = GetLastError();
+ if (write_error == ERROR_IO_PENDING) {
output_state_.is_pending = true;
DVLOG(2) << "sent pending message @" << m << " on channel @" << this
@@ -455,9 +411,7 @@ bool ChannelWin::ProcessOutgoingMessages(
return true;
}
- writing_ = false;
- last_write_error_ = write_error_;
- LOG(ERROR) << "pipe error: " << write_error_;
+ LOG(ERROR) << "pipe error: " << write_error;
return false;
}
@@ -476,7 +430,6 @@ void ChannelWin::OnIOCompleted(
DCHECK(thread_check_->CalledOnValidThread());
if (context == &input_state_.context) {
if (waiting_connect_) {
- debug_flags_ |= CONNECT_COMPLETED;
if (!ProcessConnection())
return;
// We may have some messages queued up to send...
@@ -495,11 +448,6 @@ void ChannelWin::OnIOCompleted(
// Process the new data.
if (input_state_.is_pending) {
// This is the normal case for everything except the initialization step.
- debug_flags_ |= READ_COMPLETED;
- if (debug_flags_ & WAIT_FOR_READ) {
- CHECK(!(debug_flags_ & WAIT_FOR_READ_COMPLETE));
- debug_flags_ |= WAIT_FOR_READ_COMPLETE;
- }
input_state_.is_pending = false;
if (!bytes_transfered)
ok = false;
@@ -514,14 +462,7 @@ void ChannelWin::OnIOCompleted(
ok = ProcessIncomingMessages();
} else {
DCHECK(context == &output_state_.context);
- CHECK(writing_);
CHECK(output_state_.is_pending);
- writing_ = false;
- debug_flags_ |= WRITE_COMPLETED;
- if (debug_flags_ & WAIT_FOR_WRITE) {
- CHECK(!(debug_flags_ & WAIT_FOR_WRITE_COMPLETE));
- debug_flags_ |= WAIT_FOR_WRITE_COMPLETE;
- }
ok = ProcessOutgoingMessages(context, bytes_transfered);
}
if (!ok && pipe_.IsValid()) {
diff --git a/chromium/ipc/ipc_channel_win.h b/chromium/ipc/ipc_channel_win.h
index 7a2d484159b..04990d4e84e 100644
--- a/chromium/ipc/ipc_channel_win.h
+++ b/chromium/ipc/ipc_channel_win.h
@@ -29,26 +29,24 @@ class ChannelWin : public Channel,
// Mirror methods of Channel, see ipc_channel.h for description.
ChannelWin(const IPC::ChannelHandle &channel_handle, Mode mode,
Listener* listener);
- ~ChannelWin();
+ ~ChannelWin() override;
// Channel implementation
- virtual bool Connect() override;
- virtual void Close() override;
- virtual bool Send(Message* message) override;
- virtual base::ProcessId GetPeerPID() const override;
- virtual base::ProcessId GetSelfPID() const override;
+ bool Connect() override;
+ void Close() override;
+ bool Send(Message* message) override;
+ base::ProcessId GetPeerPID() const override;
+ base::ProcessId GetSelfPID() const override;
static bool IsNamedServerInitialized(const std::string& channel_id);
private:
// ChannelReader implementation.
- virtual ReadState ReadData(char* buffer,
- int buffer_len,
- int* bytes_read) override;
- virtual bool WillDispatchInputMessage(Message* msg) override;
+ ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) override;
+ bool WillDispatchInputMessage(Message* msg) override;
bool DidEmptyInputBuffers() override;
- virtual void HandleInternalMessage(const Message& msg) override;
+ void HandleInternalMessage(const Message& msg) override;
static const base::string16 PipeName(const std::string& channel_id,
int32* secret);
@@ -59,9 +57,9 @@ class ChannelWin : public Channel,
DWORD bytes_written);
// MessageLoop::IOHandler implementation.
- virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
- DWORD bytes_transfered,
- DWORD error) override;
+ void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered,
+ DWORD error) override;
private:
struct State {
@@ -94,21 +92,9 @@ class ChannelWin : public Channel,
// Determines if we should validate a client's secret on connection.
bool validate_client_;
- // True if there is a write in progress. TODO(rvargas): remove this.
- bool writing_;
-
// Tracks the lifetime of this object, for debugging purposes.
uint32 debug_flags_;
- // OS result for the current write. TODO(rvargas): remove this.
- uint32 write_error_;
-
- // OS result for a previous failed write. TODO(rvargas): remove this.
- uint32 last_write_error_;
-
- // Size of the current write. TODO(rvargas): remove this.
- uint32 write_size_;
-
// This is a unique per-channel value used to authenticate the client end of
// a connection. If the value is non-zero, the client passes it in the hello
// and the host validates. (We don't send the zero value fto preserve IPC
diff --git a/chromium/ipc/ipc_fuzzing_tests.cc b/chromium/ipc/ipc_fuzzing_tests.cc
index f9475a1adb0..42fa8597e08 100644
--- a/chromium/ipc/ipc_fuzzing_tests.cc
+++ b/chromium/ipc/ipc_fuzzing_tests.cc
@@ -7,6 +7,8 @@
#include <sstream>
#include "base/message_loop/message_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/threading/platform_thread.h"
#include "ipc/ipc_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,14 +20,14 @@
#define IPC_MESSAGE_START TestMsgStart
-// Generic message class that is an int followed by a wstring.
-IPC_MESSAGE_CONTROL2(MsgClassIS, int, std::wstring)
+// Generic message class that is an int followed by a string16.
+IPC_MESSAGE_CONTROL2(MsgClassIS, int, base::string16)
-// Generic message class that is a wstring followed by an int.
-IPC_MESSAGE_CONTROL2(MsgClassSI, std::wstring, int)
+// Generic message class that is a string16 followed by an int.
+IPC_MESSAGE_CONTROL2(MsgClassSI, base::string16, int)
// Message to create a mutex in the IPC server, using the received name.
-IPC_MESSAGE_CONTROL2(MsgDoMutex, std::wstring, int)
+IPC_MESSAGE_CONTROL2(MsgDoMutex, base::string16, int)
// Used to generate an ID for a message that should not exist.
IPC_MESSAGE_CONTROL0(MsgUnhandled)
@@ -35,7 +37,7 @@ IPC_MESSAGE_CONTROL0(MsgUnhandled)
namespace {
TEST(IPCMessageIntegrity, ReadBeyondBufferStr) {
- //This was BUG 984408.
+ // This was BUG 984408.
uint32 v1 = kuint32max - 1;
int v2 = 666;
IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
@@ -44,11 +46,11 @@ TEST(IPCMessageIntegrity, ReadBeyondBufferStr) {
PickleIterator iter(m);
std::string vs;
- EXPECT_FALSE(m.ReadString(&iter, &vs));
+ EXPECT_FALSE(iter.ReadString(&vs));
}
-TEST(IPCMessageIntegrity, ReadBeyondBufferWStr) {
- //This was BUG 984408.
+TEST(IPCMessageIntegrity, ReadBeyondBufferStr16) {
+ // This was BUG 984408.
uint32 v1 = kuint32max - 1;
int v2 = 777;
IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
@@ -56,8 +58,8 @@ TEST(IPCMessageIntegrity, ReadBeyondBufferWStr) {
EXPECT_TRUE(m.WriteInt(v2));
PickleIterator iter(m);
- std::wstring vs;
- EXPECT_FALSE(m.ReadWString(&iter, &vs));
+ base::string16 vs;
+ EXPECT_FALSE(iter.ReadString16(&vs));
}
TEST(IPCMessageIntegrity, ReadBytesBadIterator) {
@@ -68,7 +70,7 @@ TEST(IPCMessageIntegrity, ReadBytesBadIterator) {
PickleIterator iter(m);
const char* data = NULL;
- EXPECT_TRUE(m.ReadBytes(&iter, &data, sizeof(int)));
+ EXPECT_TRUE(iter.ReadBytes(&data, sizeof(int)));
}
TEST(IPCMessageIntegrity, ReadVectorNegativeSize) {
@@ -151,13 +153,13 @@ class FuzzerServerListener : public SimpleListener {
}
private:
- void OnMsgClassISMessage(int value, const std::wstring& text) {
+ void OnMsgClassISMessage(int value, const base::string16& text) {
UseData(MsgClassIS::ID, value, text);
RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassIS::ID, value);
Cleanup();
}
- void OnMsgClassSIMessage(const std::wstring& text, int value) {
+ void OnMsgClassSIMessage(const base::string16& text, int value) {
UseData(MsgClassSI::ID, value, text);
RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassSI::ID, value);
Cleanup();
@@ -183,12 +185,13 @@ class FuzzerServerListener : public SimpleListener {
Cleanup();
}
- void UseData(int caller, int value, const std::wstring& text) {
- std::wostringstream wos;
- wos << L"IPC fuzzer:" << caller << " [" << value << L" " << text << L"]\n";
- std::wstring output = wos.str();
- LOG(WARNING) << output.c_str();
- };
+ void UseData(int caller, int value, const base::string16& text) {
+ std::ostringstream os;
+ os << "IPC fuzzer:" << caller << " [" << value << " "
+ << base::UTF16ToUTF8(text) << "]\n";
+ std::string output = os.str();
+ LOG(WARNING) << output;
+ }
int message_count_;
int pending_messages_;
@@ -211,9 +214,9 @@ class FuzzerClientListener : public SimpleListener {
int msg_value1 = 0;
int msg_value2 = 0;
PickleIterator iter(*last_msg_);
- if (!last_msg_->ReadInt(&iter, &msg_value1))
+ if (!iter.ReadInt(&msg_value1))
return false;
- if (!last_msg_->ReadInt(&iter, &msg_value2))
+ if (!iter.ReadInt(&msg_value2))
return false;
if ((msg_value2 + 1) != msg_value1)
return false;
@@ -237,7 +240,7 @@ class FuzzerClientListener : public SimpleListener {
if (FUZZER_ROUTING_ID != last_msg_->routing_id())
return false;
return (type_id == last_msg_->type());
- };
+ }
IPC::Message* last_msg_;
};
@@ -272,11 +275,11 @@ TEST_F(IPCFuzzingTest, SanityTest) {
IPC::Message* msg = NULL;
int value = 43;
- msg = new MsgClassIS(value, L"expect 43");
+ msg = new MsgClassIS(value, base::ASCIIToUTF16("expect 43"));
sender()->Send(msg);
EXPECT_TRUE(listener.ExpectMessage(value, MsgClassIS::ID));
- msg = new MsgClassSI(L"expect 44", ++value);
+ msg = new MsgClassSI(base::ASCIIToUTF16("expect 44"), ++value);
sender()->Send(msg);
EXPECT_TRUE(listener.ExpectMessage(value, MsgClassSI::ID));
@@ -304,7 +307,7 @@ TEST_F(IPCFuzzingTest, MsgBadPayloadShort) {
sender()->Send(msg);
EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID));
- msg = new MsgClassSI(L"expect one", 1);
+ msg = new MsgClassSI(base::ASCIIToUTF16("expect one"), 1);
sender()->Send(msg);
EXPECT_TRUE(listener.ExpectMessage(1, MsgClassSI::ID));
@@ -328,7 +331,7 @@ TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) {
IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
IPC::Message::PRIORITY_NORMAL);
- msg->WriteWString(L"d");
+ msg->WriteString16(base::ASCIIToUTF16("d"));
msg->WriteInt(0);
msg->WriteInt(0x65); // Extra argument.
@@ -337,7 +340,7 @@ TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) {
// Now send a well formed message to make sure the receiver wasn't
// thrown out of sync by the extra argument.
- msg = new MsgClassIS(3, L"expect three");
+ msg = new MsgClassIS(3, base::ASCIIToUTF16("expect three"));
sender()->Send(msg);
EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID));
diff --git a/chromium/ipc/ipc_logging.cc b/chromium/ipc/ipc_logging.cc
index 65d88901d93..3db4e676d15 100644
--- a/chromium/ipc/ipc_logging.cc
+++ b/chromium/ipc/ipc_logging.cc
@@ -13,9 +13,10 @@
#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "ipc/ipc_message_utils.h"
@@ -161,7 +162,7 @@ void Logging::OnPostDispatchMessage(const Message& message,
if (base::MessageLoop::current() == main_thread_) {
Log(data);
} else {
- main_thread_->PostTask(
+ main_thread_->task_runner()->PostTask(
FROM_HERE, base::Bind(&Logging::Log, base::Unretained(this), data));
}
}
@@ -231,9 +232,8 @@ void Logging::Log(const LogData& data) {
queued_logs_.push_back(data);
if (!queue_invoke_later_pending_) {
queue_invoke_later_pending_ = true;
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&Logging::OnSendLogs, base::Unretained(this)),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&Logging::OnSendLogs, base::Unretained(this)),
base::TimeDelta::FromMilliseconds(kLogSendDelayMs));
}
}
diff --git a/chromium/ipc/ipc_message.cc b/chromium/ipc/ipc_message.cc
index 7bd7a697c4f..2587b0b112b 100644
--- a/chromium/ipc/ipc_message.cc
+++ b/chromium/ipc/ipc_message.cc
@@ -7,10 +7,12 @@
#include "base/atomic_sequence_num.h"
#include "base/logging.h"
#include "build/build_config.h"
+#include "ipc/ipc_message_attachment.h"
+#include "ipc/ipc_message_attachment_set.h"
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
-#include "ipc/file_descriptor_set_posix.h"
+#include "ipc/ipc_platform_file_attachment_posix.h"
#endif
namespace {
@@ -21,9 +23,10 @@ base::StaticAtomicSequenceNumber g_ref_num;
// values has the reference number stored in the upper 24 bits, leaving the low
// 8 bits set to 0 for use as flags.
inline uint32 GetRefNumUpper24() {
- base::debug::TraceLog* trace_log = base::debug::TraceLog::GetInstance();
- int32 pid = trace_log ? trace_log->process_id() : 0;
- int32 count = g_ref_num.GetNext();
+ base::trace_event::TraceLog* trace_log =
+ base::trace_event::TraceLog::GetInstance();
+ uint32 pid = trace_log ? trace_log->process_id() : 0;
+ uint32 count = g_ref_num.GetNext();
// The 24 bit hash is composed of 14 bits of the count and 10 bits of the
// Process ID. With the current trace event buffer cap, the 14-bit count did
// not appear to wrap during a trace. Note that it is not a big deal if
@@ -71,7 +74,7 @@ Message::Message(const char* data, int data_len) : Pickle(data, data_len) {
Message::Message(const Message& other) : Pickle(other) {
Init();
#if defined(OS_POSIX)
- file_descriptor_set_ = other.file_descriptor_set_;
+ attachment_set_ = other.attachment_set_;
#endif
}
@@ -87,7 +90,7 @@ void Message::Init() {
Message& Message::operator=(const Message& other) {
*static_cast<Pickle*>(this) = other;
#if defined(OS_POSIX)
- file_descriptor_set_ = other.file_descriptor_set_;
+ attachment_set_ = other.attachment_set_;
#endif
return *this;
}
@@ -101,6 +104,11 @@ void Message::SetHeaderValues(int32 routing, uint32 type, uint32 flags) {
header()->flags = flags;
}
+void Message::EnsureMessageAttachmentSet() {
+ if (attachment_set_.get() == NULL)
+ attachment_set_ = new MessageAttachmentSet;
+}
+
#ifdef IPC_MESSAGE_LOG_ENABLED
void Message::set_sent_time(int64 time) {
DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0);
@@ -122,48 +130,34 @@ void Message::set_received_time(int64 time) const {
}
#endif
-#if defined(OS_POSIX)
-bool Message::WriteFile(base::ScopedFD descriptor) {
+bool Message::WriteAttachment(scoped_refptr<MessageAttachment> attachment) {
// We write the index of the descriptor so that we don't have to
// keep the current descriptor as extra decoding state when deserialising.
- WriteInt(file_descriptor_set()->size());
- return file_descriptor_set()->AddToOwn(descriptor.Pass());
+ WriteInt(attachment_set()->size());
+ return attachment_set()->AddAttachment(attachment);
}
-bool Message::WriteBorrowingFile(const base::PlatformFile& descriptor) {
- // We write the index of the descriptor so that we don't have to
- // keep the current descriptor as extra decoding state when deserialising.
- WriteInt(file_descriptor_set()->size());
- return file_descriptor_set()->AddToBorrow(descriptor);
-}
-
-bool Message::ReadFile(PickleIterator* iter, base::ScopedFD* descriptor) const {
+bool Message::ReadAttachment(
+ PickleIterator* iter,
+ scoped_refptr<MessageAttachment>* attachment) const {
int descriptor_index;
- if (!ReadInt(iter, &descriptor_index))
- return false;
-
- FileDescriptorSet* file_descriptor_set = file_descriptor_set_.get();
- if (!file_descriptor_set)
+ if (!iter->ReadInt(&descriptor_index))
return false;
- base::PlatformFile file =
- file_descriptor_set->TakeDescriptorAt(descriptor_index);
- if (file < 0)
+ MessageAttachmentSet* attachment_set = attachment_set_.get();
+ if (!attachment_set)
return false;
- descriptor->reset(file);
- return true;
+ *attachment = attachment_set->GetAttachmentAt(descriptor_index);
+ return nullptr != attachment->get();
}
-bool Message::HasFileDescriptors() const {
- return file_descriptor_set_.get() && !file_descriptor_set_->empty();
+bool Message::HasAttachments() const {
+ return attachment_set_.get() && !attachment_set_->empty();
}
-void Message::EnsureFileDescriptorSet() {
- if (file_descriptor_set_.get() == NULL)
- file_descriptor_set_ = new FileDescriptorSet;
+bool Message::HasMojoHandles() const {
+ return attachment_set_.get() && 0 < attachment_set_->num_mojo_handles();
}
-#endif
-
} // namespace IPC
diff --git a/chromium/ipc/ipc_message.h b/chromium/ipc/ipc_message.h
index a1b26e1d289..64d85d4d44c 100644
--- a/chromium/ipc/ipc_message.h
+++ b/chromium/ipc/ipc_message.h
@@ -8,26 +8,22 @@
#include <string>
#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
-#include "base/files/file.h"
+#include "base/memory/ref_counted.h"
#include "base/pickle.h"
+#include "base/trace_event/trace_event.h"
#include "ipc/ipc_export.h"
#if !defined(NDEBUG)
#define IPC_MESSAGE_LOG_ENABLED
#endif
-#if defined(OS_POSIX)
-#include "base/memory/ref_counted.h"
-#endif
-
-class FileDescriptorSet;
-
namespace IPC {
//------------------------------------------------------------------------------
struct LogData;
+class MessageAttachment;
+class MessageAttachmentSet;
class IPC_EXPORT Message : public Pickle {
public:
@@ -170,21 +166,17 @@ class IPC_EXPORT Message : public Pickle {
return Pickle::FindNext(sizeof(Header), range_start, range_end);
}
-#if defined(OS_POSIX)
- // On POSIX, a message supports reading / writing FileDescriptor objects.
- // This is used to pass a file descriptor to the peer of an IPC channel.
-
- // Add a descriptor to the end of the set. Returns false if the set is full.
- bool WriteFile(base::ScopedFD descriptor);
- bool WriteBorrowingFile(const base::PlatformFile& descriptor);
-
- // Get a file descriptor from the message. Returns false on error.
- // iter: a Pickle iterator to the current location in the message.
- bool ReadFile(PickleIterator* iter, base::ScopedFD* file) const;
-
- // Returns true if there are any file descriptors in this message.
- bool HasFileDescriptors() const;
-#endif
+ // WriteAttachment appends |attachment| to the end of the set. It returns
+ // false iff the set is full.
+ bool WriteAttachment(scoped_refptr<MessageAttachment> attachment);
+ // ReadAttachment parses an attachment given the parsing state |iter| and
+ // writes it to |*attachment|. It returns true on success.
+ bool ReadAttachment(PickleIterator* iter,
+ scoped_refptr<MessageAttachment>* attachment) const;
+ // Returns true if there are any attachment in this message.
+ bool HasAttachments() const;
+ // Returns true if there are any MojoHandleAttachments in this message.
+ bool HasMojoHandles() const;
#ifdef IPC_MESSAGE_LOG_ENABLED
// Adds the outgoing time from Time::Now() at the end of the message and sets
@@ -250,21 +242,19 @@ class IPC_EXPORT Message : public Pickle {
// Used internally to support IPC::Listener::OnBadMessageReceived.
mutable bool dispatch_error_;
-#if defined(OS_POSIX)
// The set of file descriptors associated with this message.
- scoped_refptr<FileDescriptorSet> file_descriptor_set_;
+ scoped_refptr<MessageAttachmentSet> attachment_set_;
- // Ensure that a FileDescriptorSet is allocated
- void EnsureFileDescriptorSet();
+ // Ensure that a MessageAttachmentSet is allocated
+ void EnsureMessageAttachmentSet();
- FileDescriptorSet* file_descriptor_set() {
- EnsureFileDescriptorSet();
- return file_descriptor_set_.get();
+ MessageAttachmentSet* attachment_set() {
+ EnsureMessageAttachmentSet();
+ return attachment_set_.get();
}
- const FileDescriptorSet* file_descriptor_set() const {
- return file_descriptor_set_.get();
+ const MessageAttachmentSet* attachment_set() const {
+ return attachment_set_.get();
}
-#endif
#ifdef IPC_MESSAGE_LOG_ENABLED
// Used for logging.
diff --git a/chromium/ipc/ipc_message_attachment.cc b/chromium/ipc/ipc_message_attachment.cc
new file mode 100644
index 00000000000..83440ae8e00
--- /dev/null
+++ b/chromium/ipc/ipc_message_attachment.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 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/ipc_message_attachment.h"
+
+namespace IPC {
+
+MessageAttachment::MessageAttachment() {
+}
+
+MessageAttachment::~MessageAttachment() {
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/ipc_message_attachment.h b/chromium/ipc/ipc_message_attachment.h
new file mode 100644
index 00000000000..ba7f0e83f90
--- /dev/null
+++ b/chromium/ipc/ipc_message_attachment.h
@@ -0,0 +1,41 @@
+// Copyright (c) 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_ATTACHMENT_H_
+#define IPC_IPC_MESSAGE_ATTACHMENT_H_
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "ipc/ipc_export.h"
+
+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::RefCounted<MessageAttachment> {
+ public:
+ enum Type {
+ TYPE_PLATFORM_FILE, // The instance is |PlatformFileAttachment|.
+ TYPE_MOJO_HANDLE, // The instance is |MojoHandleAttachment|.
+ };
+
+ virtual Type GetType() const = 0;
+
+#if defined(OS_POSIX)
+ virtual base::PlatformFile TakePlatformFile() = 0;
+#endif // OS_POSIX
+
+ protected:
+ friend class base::RefCounted<MessageAttachment>;
+ MessageAttachment();
+ virtual ~MessageAttachment();
+
+ DISALLOW_COPY_AND_ASSIGN(MessageAttachment);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_MESSAGE_ATTACHMENT_H_
diff --git a/chromium/ipc/ipc_message_attachment_set.cc b/chromium/ipc/ipc_message_attachment_set.cc
new file mode 100644
index 00000000000..cb74a5aaf07
--- /dev/null
+++ b/chromium/ipc/ipc_message_attachment_set.cc
@@ -0,0 +1,163 @@
+// 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/ipc_message_attachment_set.h"
+
+#include <algorithm>
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ipc/ipc_message_attachment.h"
+
+#if defined(OS_POSIX)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "ipc/ipc_platform_file_attachment_posix.h"
+#endif // OS_POSIX
+
+namespace IPC {
+
+MessageAttachmentSet::MessageAttachmentSet()
+ : consumed_descriptor_highwater_(0) {
+}
+
+MessageAttachmentSet::~MessageAttachmentSet() {
+ if (consumed_descriptor_highwater_ == size())
+ return;
+
+ // We close all the owning descriptors. If this message should have
+ // been transmitted, then closing those with close flags set mirrors
+ // the expected behaviour.
+ //
+ // If this message was received with more descriptors than expected
+ // (which could a DOS against the browser by a rogue renderer) then all
+ // the descriptors have their close flag set and we free all the extra
+ // kernel resources.
+ LOG(WARNING) << "MessageAttachmentSet destroyed with unconsumed descriptors: "
+ << consumed_descriptor_highwater_ << "/" << size();
+}
+
+unsigned MessageAttachmentSet::num_descriptors() const {
+ return std::count_if(attachments_.begin(), attachments_.end(),
+ [](scoped_refptr<MessageAttachment> i) {
+ return i->GetType() == MessageAttachment::TYPE_PLATFORM_FILE;
+ });
+}
+
+unsigned MessageAttachmentSet::num_mojo_handles() const {
+ return std::count_if(attachments_.begin(), attachments_.end(),
+ [](scoped_refptr<MessageAttachment> i) {
+ return i->GetType() == MessageAttachment::TYPE_MOJO_HANDLE;
+ });
+}
+
+unsigned MessageAttachmentSet::size() const {
+ return static_cast<unsigned>(attachments_.size());
+}
+
+bool MessageAttachmentSet::AddAttachment(
+ scoped_refptr<MessageAttachment> attachment) {
+#if defined(OS_POSIX)
+ if (attachment->GetType() == MessageAttachment::TYPE_PLATFORM_FILE &&
+ num_descriptors() == kMaxDescriptorsPerMessage) {
+ DLOG(WARNING) << "Cannot add file descriptor. MessageAttachmentSet full.";
+ return false;
+ }
+#endif
+
+ attachments_.push_back(attachment);
+ return true;
+}
+
+scoped_refptr<MessageAttachment> MessageAttachmentSet::GetAttachmentAt(
+ unsigned index) {
+ if (index >= size()) {
+ DLOG(WARNING) << "Accessing out of bound index:" << index << "/" << size();
+ return scoped_refptr<MessageAttachment>();
+ }
+
+ // We should always walk the descriptors in order, so it's reasonable to
+ // enforce this. Consider the case where a compromised renderer sends us
+ // the following message:
+ //
+ // ExampleMsg:
+ // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
+ //
+ // Here the renderer sent us a message which should have a descriptor, but
+ // actually sent two in an attempt to fill our fd table and kill us. By
+ // setting the index of the descriptor in the message to 1 (it should be
+ // 0), we would record a highwater of 1 and then consider all the
+ // descriptors to have been used.
+ //
+ // So we can either track of the use of each descriptor in a bitset, or we
+ // can enforce that we walk the indexes strictly in order.
+ //
+ // There's one more wrinkle: When logging messages, we may reparse them. So
+ // we have an exception: When the consumed_descriptor_highwater_ is at the
+ // end of the array and index 0 is requested, we reset the highwater value.
+ // TODO(morrita): This is absurd. This "wringle" disallow to introduce clearer
+ // ownership model. Only client is NaclIPCAdapter. See crbug.com/415294
+ if (index == 0 && consumed_descriptor_highwater_ == size())
+ consumed_descriptor_highwater_ = 0;
+
+ if (index != consumed_descriptor_highwater_)
+ return scoped_refptr<MessageAttachment>();
+
+ consumed_descriptor_highwater_ = index + 1;
+
+ return attachments_[index];
+}
+
+void MessageAttachmentSet::CommitAll() {
+ attachments_.clear();
+ consumed_descriptor_highwater_ = 0;
+}
+
+#if defined(OS_POSIX)
+
+void MessageAttachmentSet::PeekDescriptors(base::PlatformFile* buffer) const {
+ for (size_t i = 0; i != attachments_.size(); ++i)
+ buffer[i] = internal::GetPlatformFile(attachments_[i]);
+}
+
+bool MessageAttachmentSet::ContainsDirectoryDescriptor() const {
+ struct stat st;
+
+ for (auto i = attachments_.begin(); i != attachments_.end(); ++i) {
+ if (fstat(internal::GetPlatformFile(*i), &st) == 0 && S_ISDIR(st.st_mode))
+ return true;
+ }
+
+ return false;
+}
+
+void MessageAttachmentSet::ReleaseFDsToClose(
+ std::vector<base::PlatformFile>* fds) {
+ for (size_t i = 0; i < attachments_.size(); ++i) {
+ internal::PlatformFileAttachment* file =
+ static_cast<internal::PlatformFileAttachment*>(attachments_[i].get());
+ if (file->Owns())
+ fds->push_back(file->TakePlatformFile());
+ }
+
+ CommitAll();
+}
+
+void MessageAttachmentSet::AddDescriptorsToOwn(const base::PlatformFile* buffer,
+ unsigned count) {
+ DCHECK(count <= kMaxDescriptorsPerMessage);
+ DCHECK_EQ(num_descriptors(), 0u);
+ DCHECK_EQ(consumed_descriptor_highwater_, 0u);
+
+ attachments_.reserve(count);
+ for (unsigned i = 0; i < count; ++i)
+ AddAttachment(
+ new internal::PlatformFileAttachment(base::ScopedFD(buffer[i])));
+}
+
+#endif // OS_POSIX
+
+} // namespace IPC
+
+
diff --git a/chromium/ipc/file_descriptor_set_posix.h b/chromium/ipc/ipc_message_attachment_set.h
index d454962e84f..7e848bd3f54 100644
--- a/chromium/ipc/file_descriptor_set_posix.h
+++ b/chromium/ipc/ipc_message_attachment_set.h
@@ -2,67 +2,70 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef IPC_FILE_DESCRIPTOR_SET_POSIX_H_
-#define IPC_FILE_DESCRIPTOR_SET_POSIX_H_
+#ifndef IPC_IPC_MESSAGE_ATTACHMENT_SET_H_
+#define IPC_IPC_MESSAGE_ATTACHMENT_SET_H_
#include <vector>
#include "base/basictypes.h"
-#include "base/files/file.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "ipc/ipc_export.h"
-// -----------------------------------------------------------------------------
-// A FileDescriptorSet is an ordered set of POSIX file descriptors. These are
-// associated with IPC messages so that descriptors can be transmitted over a
-// UNIX domain socket.
-// -----------------------------------------------------------------------------
-class IPC_EXPORT FileDescriptorSet
- : public base::RefCountedThreadSafe<FileDescriptorSet> {
- public:
- FileDescriptorSet();
-
- // This is the maximum number of descriptors per message. We need to know this
- // because the control message kernel interface has to be given a buffer which
- // is large enough to store all the descriptor numbers. Otherwise the kernel
- // tells us that it truncated the control data and the extra descriptors are
- // lost.
- //
- // In debugging mode, it's a fatal error to try and add more than this number
- // of descriptors to a FileDescriptorSet.
- static const size_t kMaxDescriptorsPerMessage = 7;
-
- // ---------------------------------------------------------------------------
- // Interfaces for building during message serialisation...
+#if defined(OS_POSIX)
+#include "base/files/file.h"
+#endif
- // Add a descriptor to the end of the set. Returns false iff the set is full.
- bool AddToBorrow(base::PlatformFile fd);
- // Add a descriptor to the end of the set and automatically close it after
- // transmission. Returns false iff the set is full.
- bool AddToOwn(base::ScopedFD fd);
+namespace IPC {
- // ---------------------------------------------------------------------------
+class MessageAttachment;
+// -----------------------------------------------------------------------------
+// A MessageAttachmentSet is an ordered set of MessageAttachment objects. These
+// are associated with IPC messages so that attachments, each of which is either
+// a platform file or a mojo handle, can be transmitted over the underlying UNIX
+// domain socket (for ChannelPosix) or Mojo MessagePipe (for ChannelMojo).
+// -----------------------------------------------------------------------------
+class IPC_EXPORT MessageAttachmentSet
+ : public base::RefCountedThreadSafe<MessageAttachmentSet> {
+ public:
+ MessageAttachmentSet();
- // ---------------------------------------------------------------------------
- // Interfaces for accessing during message deserialisation...
+ // Return the number of attachments
+ unsigned size() const;
+ // Return the number of file descriptors
+ unsigned num_descriptors() const;
+ // Return the number of mojo handles in the attachment set
+ unsigned num_mojo_handles() const;
- // Return the number of descriptors
- unsigned size() const { return descriptors_.size(); }
// Return true if no unconsumed descriptors remain
bool empty() const { return 0 == size(); }
- // Take the nth descriptor from the beginning of the set,
- // transferring the ownership of the descriptor taken. Code using this
- // /must/ access the descriptors in order, and must do it at most once.
+
+ bool AddAttachment(scoped_refptr<MessageAttachment> attachment);
+
+ // Take the nth attachment from the beginning of the set, Code using this
+ // /must/ access the attachments in order, and must do it at most once.
//
// This interface is designed for the deserialising code as it doesn't
// support close flags.
- // returns: file descriptor, or -1 on error
- base::PlatformFile TakeDescriptorAt(unsigned n);
+ // returns: an attachment, or nullptr on error
+ scoped_refptr<MessageAttachment> GetAttachmentAt(unsigned index);
- // ---------------------------------------------------------------------------
+ // This must be called after transmitting the descriptors returned by
+ // PeekDescriptors. It marks all the descriptors as consumed and closes those
+ // which are auto-close.
+ void CommitAll();
+#if defined(OS_POSIX)
+ // This is the maximum number of descriptors per message. We need to know this
+ // because the control message kernel interface has to be given a buffer which
+ // is large enough to store all the descriptor numbers. Otherwise the kernel
+ // tells us that it truncated the control data and the extra descriptors are
+ // lost.
+ //
+ // In debugging mode, it's a fatal error to try and add more than this number
+ // of descriptors to a MessageAttachmentSet.
+ static const size_t kMaxDescriptorsPerMessage = 7;
// ---------------------------------------------------------------------------
// Interfaces for transmission...
@@ -71,10 +74,6 @@ class IPC_EXPORT FileDescriptorSet
// must be called after these descriptors have been transmitted.
// buffer: (output) a buffer of, at least, size() integers.
void PeekDescriptors(base::PlatformFile* buffer) const;
- // This must be called after transmitting the descriptors returned by
- // PeekDescriptors. It marks all the descriptors as consumed and closes those
- // which are auto-close.
- void CommitAll();
// Returns true if any contained file descriptors appear to be handles to a
// directory.
bool ContainsDirectoryDescriptor() const;
@@ -84,7 +83,6 @@ class IPC_EXPORT FileDescriptorSet
// ---------------------------------------------------------------------------
-
// ---------------------------------------------------------------------------
// Interfaces for receiving...
@@ -93,19 +91,18 @@ class IPC_EXPORT FileDescriptorSet
// unconsumed descriptors are closed on destruction.
void AddDescriptorsToOwn(const base::PlatformFile* buffer, unsigned count);
+#endif // OS_POSIX
+
// ---------------------------------------------------------------------------
private:
- friend class base::RefCountedThreadSafe<FileDescriptorSet>;
+ friend class base::RefCountedThreadSafe<MessageAttachmentSet>;
- ~FileDescriptorSet();
+ ~MessageAttachmentSet();
- // A vector of descriptors and close flags. If this message is sent, then
- // these descriptors are sent as control data. After sending, any descriptors
- // with a true flag are closed. If this message has been received, then these
- // are the descriptors which were received and all close flags are true.
- std::vector<base::PlatformFile> descriptors_;
- ScopedVector<base::ScopedFD> owned_descriptors_;
+ // A vector of attachments of the message, which might be |PlatformFile| or
+ // |MessagePipe|.
+ std::vector<scoped_refptr<MessageAttachment>> attachments_;
// This contains the index of the next descriptor which should be consumed.
// It's used in a couple of ways. Firstly, at destruction we can check that
@@ -113,7 +110,9 @@ class IPC_EXPORT FileDescriptorSet
// can check that they are read in order.
mutable unsigned consumed_descriptor_highwater_;
- DISALLOW_COPY_AND_ASSIGN(FileDescriptorSet);
+ DISALLOW_COPY_AND_ASSIGN(MessageAttachmentSet);
};
-#endif // IPC_FILE_DESCRIPTOR_SET_POSIX_H_
+} // namespace IPC
+
+#endif // IPC_IPC_MESSAGE_ATTACHMENT_SET_H_
diff --git a/chromium/ipc/ipc_message_attachment_set_posix_unittest.cc b/chromium/ipc/ipc_message_attachment_set_posix_unittest.cc
new file mode 100644
index 00000000000..416a7d2589c
--- /dev/null
+++ b/chromium/ipc/ipc_message_attachment_set_posix_unittest.cc
@@ -0,0 +1,201 @@
+// 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.
+
+// This test is POSIX only.
+
+#include "ipc/ipc_message_attachment_set.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/posix/eintr_wrapper.h"
+#include "ipc/ipc_platform_file_attachment_posix.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace IPC {
+namespace {
+
+// Get a safe file descriptor for test purposes.
+int GetSafeFd() {
+ return open("/dev/null", O_RDONLY);
+}
+
+// Returns true if fd was already closed. Closes fd if not closed.
+bool VerifyClosed(int fd) {
+ const int duped = dup(fd);
+ if (duped != -1) {
+ EXPECT_NE(IGNORE_EINTR(close(duped)), -1);
+ EXPECT_NE(IGNORE_EINTR(close(fd)), -1);
+ return false;
+ }
+ return true;
+}
+
+// The MessageAttachmentSet will try and close some of the descriptor numbers
+// which we given it. This is the base descriptor value. It's great enough such
+// that no real descriptor will accidently be closed.
+static const int kFDBase = 50000;
+
+TEST(MessageAttachmentSet, BasicAdd) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ ASSERT_EQ(set->size(), 0u);
+ ASSERT_TRUE(set->empty());
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase)));
+ ASSERT_EQ(set->size(), 1u);
+ ASSERT_TRUE(!set->empty());
+
+ // Empties the set and stops a warning about deleting a set with unconsumed
+ // descriptors
+ set->CommitAll();
+}
+
+TEST(MessageAttachmentSet, BasicAddAndClose) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ ASSERT_EQ(set->size(), 0u);
+ ASSERT_TRUE(set->empty());
+ const int fd = GetSafeFd();
+ ASSERT_TRUE(set->AddAttachment(
+ new internal::PlatformFileAttachment(base::ScopedFD(fd))));
+ ASSERT_EQ(set->size(), 1u);
+ ASSERT_TRUE(!set->empty());
+
+ set->CommitAll();
+
+ ASSERT_TRUE(VerifyClosed(fd));
+}
+TEST(MessageAttachmentSet, MaxSize) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ for (size_t i = 0; i < MessageAttachmentSet::kMaxDescriptorsPerMessage; ++i)
+ ASSERT_TRUE(set->AddAttachment(
+ new internal::PlatformFileAttachment(kFDBase + 1 + i)));
+
+ ASSERT_TRUE(
+ !set->AddAttachment(new internal::PlatformFileAttachment(kFDBase)));
+
+ set->CommitAll();
+}
+
+TEST(MessageAttachmentSet, SetDescriptors) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ ASSERT_TRUE(set->empty());
+ set->AddDescriptorsToOwn(NULL, 0);
+ ASSERT_TRUE(set->empty());
+
+ const int fd = GetSafeFd();
+ static const int fds[] = {fd};
+ set->AddDescriptorsToOwn(fds, 1);
+ ASSERT_TRUE(!set->empty());
+ ASSERT_EQ(set->size(), 1u);
+
+ set->CommitAll();
+
+ ASSERT_TRUE(VerifyClosed(fd));
+}
+
+TEST(MessageAttachmentSet, PeekDescriptors) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ set->PeekDescriptors(NULL);
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase)));
+
+ int fds[1];
+ fds[0] = 0;
+ set->PeekDescriptors(fds);
+ ASSERT_EQ(fds[0], kFDBase);
+ set->CommitAll();
+ ASSERT_TRUE(set->empty());
+}
+
+TEST(MessageAttachmentSet, WalkInOrder) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
+ // used to retrieve borrowed descriptors. That never happens in production.
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase)));
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase + 1)));
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase + 2)));
+
+ ASSERT_EQ(set->GetAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetAttachmentAt(1)->TakePlatformFile(), kFDBase + 1);
+ ASSERT_EQ(set->GetAttachmentAt(2)->TakePlatformFile(), kFDBase + 2);
+
+ set->CommitAll();
+}
+
+TEST(MessageAttachmentSet, WalkWrongOrder) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
+ // used to retrieve borrowed descriptors. That never happens in production.
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase)));
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase + 1)));
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase + 2)));
+
+ ASSERT_EQ(set->GetAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetAttachmentAt(2), nullptr);
+
+ set->CommitAll();
+}
+
+TEST(MessageAttachmentSet, WalkCycle) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
+ // used to retrieve borrowed descriptors. That never happens in production.
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase)));
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase + 1)));
+ ASSERT_TRUE(
+ set->AddAttachment(new internal::PlatformFileAttachment(kFDBase + 2)));
+
+ ASSERT_EQ(set->GetAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetAttachmentAt(1)->TakePlatformFile(), kFDBase + 1);
+ ASSERT_EQ(set->GetAttachmentAt(2)->TakePlatformFile(), kFDBase + 2);
+ ASSERT_EQ(set->GetAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetAttachmentAt(1)->TakePlatformFile(), kFDBase + 1);
+ ASSERT_EQ(set->GetAttachmentAt(2)->TakePlatformFile(), kFDBase + 2);
+ ASSERT_EQ(set->GetAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetAttachmentAt(1)->TakePlatformFile(), kFDBase + 1);
+ ASSERT_EQ(set->GetAttachmentAt(2)->TakePlatformFile(), kFDBase + 2);
+
+ set->CommitAll();
+}
+
+TEST(MessageAttachmentSet, DontClose) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ const int fd = GetSafeFd();
+ ASSERT_TRUE(set->AddAttachment(new internal::PlatformFileAttachment(fd)));
+ set->CommitAll();
+
+ ASSERT_FALSE(VerifyClosed(fd));
+}
+
+TEST(MessageAttachmentSet, DoClose) {
+ scoped_refptr<MessageAttachmentSet> set(new MessageAttachmentSet);
+
+ const int fd = GetSafeFd();
+ ASSERT_TRUE(set->AddAttachment(
+ new internal::PlatformFileAttachment(base::ScopedFD(fd))));
+ set->CommitAll();
+
+ ASSERT_TRUE(VerifyClosed(fd));
+}
+
+} // namespace
+} // namespace IPC
diff --git a/chromium/ipc/ipc_message_macros.h b/chromium/ipc/ipc_message_macros.h
index 20c83350733..e0e16d55925 100644
--- a/chromium/ipc/ipc_message_macros.h
+++ b/chromium/ipc/ipc_message_macros.h
@@ -457,7 +457,7 @@
void (T::*func)(P*, TA)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(parameter, p.a); \
+ (obj->*func)(parameter, get<0>(p)); \
return true; \
} \
return false; \
@@ -469,7 +469,7 @@
void (T::*func)(P*, TA, TB)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(parameter, p.a, p.b); \
+ (obj->*func)(parameter, get<0>(p), get<1>(p)); \
return true; \
} \
return false; \
@@ -481,7 +481,7 @@
void (T::*func)(P*, TA, TB, TC)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(parameter, p.a, p.b, p.c); \
+ (obj->*func)(parameter, get<0>(p), get<1>(p), get<2>(p)); \
return true; \
} \
return false; \
@@ -494,7 +494,7 @@
void (T::*func)(P*, TA, TB, TC, TD)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(parameter, p.a, p.b, p.c, p.d); \
+ (obj->*func)(parameter, get<0>(p), get<1>(p), get<2>(p), get<3>(p)); \
return true; \
} \
return false; \
@@ -507,7 +507,8 @@
void (T::*func)(P*, TA, TB, TC, TD, TE)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(parameter, p.a, p.b, p.c, p.d, p.e); \
+ (obj->*func)(parameter, get<0>(p), get<1>(p), get<2>(p), get<3>(p), \
+ get<4>(p)); \
return true; \
} \
return false; \
@@ -817,18 +818,18 @@
#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() Tuple0
-#define IPC_TUPLE_IN_1(t1) Tuple1<t1>
-#define IPC_TUPLE_IN_2(t1, t2) Tuple2<t1, t2>
-#define IPC_TUPLE_IN_3(t1, t2, t3) Tuple3<t1, t2, t3>
-#define IPC_TUPLE_IN_4(t1, t2, t3, t4) Tuple4<t1, t2, t3, t4>
-#define IPC_TUPLE_IN_5(t1, t2, t3, t4, t5) Tuple5<t1, t2, t3, t4, t5>
+#define IPC_TUPLE_IN_0() Tuple<>
+#define IPC_TUPLE_IN_1(t1) Tuple<t1>
+#define IPC_TUPLE_IN_2(t1, t2) Tuple<t1, t2>
+#define IPC_TUPLE_IN_3(t1, t2, t3) Tuple<t1, t2, t3>
+#define IPC_TUPLE_IN_4(t1, t2, t3, t4) Tuple<t1, t2, t3, t4>
+#define IPC_TUPLE_IN_5(t1, t2, t3, t4, t5) Tuple<t1, t2, t3, t4, t5>
-#define IPC_TUPLE_OUT_0() Tuple0
-#define IPC_TUPLE_OUT_1(t1) Tuple1<t1&>
-#define IPC_TUPLE_OUT_2(t1, t2) Tuple2<t1&, t2&>
-#define IPC_TUPLE_OUT_3(t1, t2, t3) Tuple3<t1&, t2&, t3&>
-#define IPC_TUPLE_OUT_4(t1, t2, t3, t4) Tuple4<t1&, t2&, t3&, t4&>
+#define IPC_TUPLE_OUT_0() Tuple<>
+#define IPC_TUPLE_OUT_1(t1) Tuple<t1&>
+#define IPC_TUPLE_OUT_2(t1, t2) Tuple<t1&, t2&>
+#define IPC_TUPLE_OUT_3(t1, t2, t3) Tuple<t1&, t2&, t3&>
+#define IPC_TUPLE_OUT_4(t1, t2, t3, t4) Tuple<t1&, t2&, t3&, t4&>
#define IPC_NAME_IN_0() MakeTuple()
#define IPC_NAME_IN_1(t1) MakeRefTuple(arg1)
@@ -966,14 +967,7 @@
#endif // IPC_IPC_MESSAGE_MACROS_H_
-// The following #ifdef cannot be removed. Although the code is semantically
-// equivalent without the #ifdef, VS2013 contains a bug where it is
-// over-aggressive in optimizing out #includes. Putting the #ifdef is a
-// workaround for this bug. See http://goo.gl/eGt2Fb for more details.
-// This can be removed once VS2013 is fixed.
-#ifdef IPC_MESSAGE_START
// Clean up IPC_MESSAGE_START in this unguarded section so that the
// XXX_messages.h files need not do so themselves. This makes the
// XXX_messages.h files easier to write.
#undef IPC_MESSAGE_START
-#endif
diff --git a/chromium/ipc/ipc_message_start.h b/chromium/ipc/ipc_message_start.h
index f7b4be8f526..d4966bc4196 100644
--- a/chromium/ipc/ipc_message_start.h
+++ b/chromium/ipc/ipc_message_start.h
@@ -35,7 +35,6 @@ enum IPCMessageStart {
AutofillMsgStart,
SafeBrowsingMsgStart,
P2PMsgStart,
- SocketStreamMsgStart,
ResourceMsgStart,
FileSystemMsgStart,
ChildProcessMsgStart,
@@ -45,8 +44,6 @@ enum IPCMessageStart {
DeviceLightMsgStart,
DeviceMotionMsgStart,
DeviceOrientationMsgStart,
- DesktopNotificationMsgStart,
- GeolocationMsgStart,
AudioMsgStart,
MidiMsgStart,
ChromeMsgStart,
@@ -86,6 +83,7 @@ enum IPCMessageStart {
LocalDiscoveryMsgStart,
PowerMonitorMsgStart,
EncryptedMediaMsgStart,
+ CacheStorageMsgStart,
ServiceWorkerMsgStart,
MessagePortMsgStart,
EmbeddedWorkerMsgStart,
@@ -100,7 +98,6 @@ enum IPCMessageStart {
CldDataProviderMsgStart,
PushMessagingMsgStart,
GinJavaBridgeMsgStart,
- BatteryStatusMsgStart,
ChromeUtilityPrintingMsgStart,
AecDumpMsgStart,
OzoneGpuMsgStart,
@@ -113,6 +110,20 @@ enum IPCMessageStart {
ExtensionUtilityMsgStart,
GeofencingMsgStart,
LayoutTestMsgStart,
+ NetworkHintsMsgStart,
+ BluetoothMsgStart,
+ NavigatorConnectMsgStart,
+ CastMediaMsgStart,
+ AwMessagePortMsgStart,
+ ExtensionsGuestViewMsgStart,
+ GuestViewMsgStart,
+ // Note: CastCryptoMsgStart and CastChannelMsgStart reserved for Chromecast
+ // internal code. Contact gunsch@ before changing/removing.
+ CastCryptoMsgStart,
+ CastChannelMsgStart,
+ DataReductionProxyStart,
+ ContentSettingsMsgStart,
+ ChromeAppBannerMsgStart,
LastIPCMsgStart // Must come last.
};
diff --git a/chromium/ipc/ipc_message_utils.cc b/chromium/ipc/ipc_message_utils.cc
index be8795b00ef..adb14d1d56c 100644
--- a/chromium/ipc/ipc_message_utils.cc
+++ b/chromium/ipc/ipc_message_utils.cc
@@ -13,10 +13,14 @@
#include "base/time/time.h"
#include "base/values.h"
#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_message_attachment.h"
+#include "ipc/ipc_message_attachment_set.h"
#if defined(OS_POSIX)
-#include "ipc/file_descriptor_set_posix.h"
-#elif defined(OS_WIN)
+#include "ipc/ipc_platform_file_attachment_posix.h"
+#endif
+
+#if defined(OS_WIN)
#include <tchar.h>
#endif
@@ -175,7 +179,7 @@ bool ReadValue(const Message* m, PickleIterator* iter, base::Value** value,
switch (type) {
case base::Value::TYPE_NULL:
- *value = base::Value::CreateNullValue();
+ *value = base::Value::CreateNullValue().release();
break;
case base::Value::TYPE_BOOLEAN: {
bool val;
@@ -208,7 +212,7 @@ bool ReadValue(const Message* m, PickleIterator* iter, base::Value** value,
case base::Value::TYPE_BINARY: {
const char* data;
int length;
- if (!m->ReadData(iter, &data, &length))
+ if (!iter->ReadData(&data, &length))
return false;
*value = base::BinaryValue::CreateWithCopiedBuffer(data, length);
break;
@@ -260,7 +264,7 @@ void ParamTraits<unsigned char>::Write(Message* m, const param_type& p) {
bool ParamTraits<unsigned char>::Read(const Message* m, PickleIterator* iter,
param_type* r) {
const char* data;
- if (!m->ReadBytes(iter, &data, sizeof(param_type)))
+ if (!iter->ReadBytes(&data, sizeof(param_type)))
return false;
memcpy(r, data, sizeof(param_type));
return true;
@@ -277,7 +281,7 @@ void ParamTraits<unsigned short>::Write(Message* m, const param_type& p) {
bool ParamTraits<unsigned short>::Read(const Message* m, PickleIterator* iter,
param_type* r) {
const char* data;
- if (!m->ReadBytes(iter, &data, sizeof(param_type)))
+ if (!iter->ReadBytes(&data, sizeof(param_type)))
return false;
memcpy(r, data, sizeof(param_type));
return true;
@@ -322,7 +326,7 @@ void ParamTraits<double>::Write(Message* m, const param_type& p) {
bool ParamTraits<double>::Read(const Message* m, PickleIterator* iter,
param_type* r) {
const char *data;
- if (!m->ReadBytes(iter, &data, sizeof(*r))) {
+ if (!iter->ReadBytes(&data, sizeof(*r))) {
NOTREACHED();
return false;
}
@@ -339,15 +343,9 @@ void ParamTraits<std::string>::Log(const param_type& p, std::string* l) {
l->append(p);
}
-void ParamTraits<std::wstring>::Log(const param_type& p, std::string* l) {
- l->append(base::WideToUTF8(p));
-}
-
-#if !defined(WCHAR_T_IS_UTF16)
void ParamTraits<base::string16>::Log(const param_type& p, std::string* l) {
l->append(base::UTF16ToUTF8(p));
}
-#endif
void ParamTraits<std::vector<char> >::Write(Message* m, const param_type& p) {
if (p.empty()) {
@@ -362,7 +360,7 @@ bool ParamTraits<std::vector<char> >::Read(const Message* m,
param_type* r) {
const char *data;
int data_size = 0;
- if (!m->ReadData(iter, &data, &data_size) || data_size < 0)
+ if (!iter->ReadData(&data, &data_size) || data_size < 0)
return false;
r->resize(data_size);
if (data_size)
@@ -389,7 +387,7 @@ bool ParamTraits<std::vector<unsigned char> >::Read(const Message* m,
param_type* r) {
const char *data;
int data_size = 0;
- if (!m->ReadData(iter, &data, &data_size) || data_size < 0)
+ if (!iter->ReadData(&data, &data_size) || data_size < 0)
return false;
r->resize(data_size);
if (data_size)
@@ -416,7 +414,7 @@ bool ParamTraits<std::vector<bool> >::Read(const Message* m,
param_type* r) {
int size;
// ReadLength() checks for < 0 itself.
- if (!m->ReadLength(iter, &size))
+ if (!iter->ReadLength(&size))
return false;
r->resize(size);
for (int i = 0; i < size; i++) {
@@ -466,10 +464,11 @@ void ParamTraits<base::FileDescriptor>::Write(Message* m, const param_type& p) {
return;
if (p.auto_close) {
- if (!m->WriteFile(base::ScopedFD(p.fd)))
+ if (!m->WriteAttachment(
+ new internal::PlatformFileAttachment(base::ScopedFD(p.fd))))
NOTREACHED();
} else {
- if (!m->WriteBorrowingFile(p.fd))
+ if (!m->WriteAttachment(new internal::PlatformFileAttachment(p.fd)))
NOTREACHED();
}
}
@@ -487,11 +486,11 @@ bool ParamTraits<base::FileDescriptor>::Read(const Message* m,
if (!valid)
return true;
- base::ScopedFD fd;
- if (!m->ReadFile(iter, &fd))
+ scoped_refptr<MessageAttachment> attachment;
+ if (!m->ReadAttachment(iter, &attachment))
return false;
- *r = base::FileDescriptor(fd.release(), true);
+ *r = base::FileDescriptor(attachment->TakePlatformFile(), true);
return true;
}
@@ -727,7 +726,7 @@ void ParamTraits<Message>::Write(Message* 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.
- DCHECK(!p.HasFileDescriptors());
+ DCHECK(!p.HasAttachments());
#endif
// Don't just write out the message. This is used to send messages between
@@ -749,14 +748,14 @@ void ParamTraits<Message>::Write(Message* m, const Message& p) {
bool ParamTraits<Message>::Read(const Message* m, PickleIterator* iter,
Message* r) {
uint32 routing_id, type, flags;
- if (!m->ReadUInt32(iter, &routing_id) ||
- !m->ReadUInt32(iter, &type) ||
- !m->ReadUInt32(iter, &flags))
+ if (!iter->ReadUInt32(&routing_id) ||
+ !iter->ReadUInt32(&type) ||
+ !iter->ReadUInt32(&flags))
return false;
int payload_size;
const char* payload;
- if (!m->ReadData(iter, &payload, &payload_size))
+ if (!iter->ReadData(&payload, &payload_size))
return false;
r->SetHeaderValues(static_cast<int32>(routing_id), type, flags);
@@ -777,7 +776,7 @@ void ParamTraits<HANDLE>::Write(Message* m, const param_type& p) {
bool ParamTraits<HANDLE>::Read(const Message* m, PickleIterator* iter,
param_type* r) {
int32 temp;
- if (!m->ReadInt(iter, &temp))
+ if (!iter->ReadInt(&temp))
return false;
*r = LongToHandle(temp);
return true;
@@ -795,7 +794,7 @@ bool ParamTraits<LOGFONT>::Read(const Message* m, PickleIterator* iter,
param_type* r) {
const char *data;
int data_size = 0;
- if (m->ReadData(iter, &data, &data_size) && data_size == sizeof(LOGFONT)) {
+ if (iter->ReadData(&data, &data_size) && data_size == sizeof(LOGFONT)) {
const LOGFONT *font = reinterpret_cast<LOGFONT*>(const_cast<char*>(data));
if (_tcsnlen(font->lfFaceName, LF_FACESIZE) < LF_FACESIZE) {
memcpy(r, data, sizeof(LOGFONT));
@@ -819,7 +818,7 @@ bool ParamTraits<MSG>::Read(const Message* m, PickleIterator* iter,
param_type* r) {
const char *data;
int data_size = 0;
- bool result = m->ReadData(iter, &data, &data_size);
+ bool result = iter->ReadData(&data, &data_size);
if (result && data_size == sizeof(MSG)) {
memcpy(r, data, sizeof(MSG));
} else {
diff --git a/chromium/ipc/ipc_message_utils.h b/chromium/ipc/ipc_message_utils.h
index 8351b178b2b..6787c8e2eb8 100644
--- a/chromium/ipc/ipc_message_utils.h
+++ b/chromium/ipc/ipc_message_utils.h
@@ -117,7 +117,7 @@ struct ParamTraits<bool> {
m->WriteBool(p);
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return m->ReadBool(iter, r);
+ return iter->ReadBool(r);
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
@@ -145,7 +145,7 @@ struct ParamTraits<int> {
m->WriteInt(p);
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return m->ReadInt(iter, r);
+ return iter->ReadInt(r);
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
@@ -157,7 +157,7 @@ struct ParamTraits<unsigned int> {
m->WriteInt(p);
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return m->ReadInt(iter, reinterpret_cast<int*>(r));
+ return iter->ReadInt(reinterpret_cast<int*>(r));
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
@@ -169,7 +169,7 @@ struct ParamTraits<long> {
m->WriteLongUsingDangerousNonPortableLessPersistableForm(p);
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return m->ReadLong(iter, r);
+ return iter->ReadLong(r);
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
@@ -181,7 +181,7 @@ struct ParamTraits<unsigned long> {
m->WriteLongUsingDangerousNonPortableLessPersistableForm(p);
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return m->ReadLong(iter, reinterpret_cast<long*>(r));
+ return iter->ReadLong(reinterpret_cast<long*>(r));
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
@@ -194,7 +194,7 @@ struct ParamTraits<long long> {
}
static bool Read(const Message* m, PickleIterator* iter,
param_type* r) {
- return m->ReadInt64(iter, reinterpret_cast<int64*>(r));
+ return iter->ReadInt64(reinterpret_cast<int64*>(r));
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
@@ -207,7 +207,7 @@ struct ParamTraits<unsigned long long> {
}
static bool Read(const Message* m, PickleIterator* iter,
param_type* r) {
- return m->ReadInt64(iter, reinterpret_cast<int64*>(r));
+ return iter->ReadInt64(reinterpret_cast<int64*>(r));
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
@@ -222,7 +222,7 @@ struct IPC_EXPORT ParamTraits<float> {
m->WriteFloat(p);
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return m->ReadFloat(iter, r);
+ return iter->ReadFloat(r);
}
static void Log(const param_type& p, std::string* l);
};
@@ -245,28 +245,12 @@ struct ParamTraits<std::string> {
}
static bool Read(const Message* m, PickleIterator* iter,
param_type* r) {
- return m->ReadString(iter, r);
+ return iter->ReadString(r);
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
template <>
-struct ParamTraits<std::wstring> {
- typedef std::wstring param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteWString(p);
- }
- static bool Read(const Message* m, PickleIterator* iter,
- param_type* r) {
- return m->ReadWString(iter, r);
- }
- IPC_EXPORT static void Log(const param_type& p, std::string* l);
-};
-
-// If WCHAR_T_IS_UTF16 is defined, then string16 is a std::wstring so we don't
-// need this trait.
-#if !defined(WCHAR_T_IS_UTF16)
-template <>
struct ParamTraits<base::string16> {
typedef base::string16 param_type;
static void Write(Message* m, const param_type& p) {
@@ -274,11 +258,10 @@ struct ParamTraits<base::string16> {
}
static bool Read(const Message* m, PickleIterator* iter,
param_type* r) {
- return m->ReadString16(iter, r);
+ return iter->ReadString16(r);
}
IPC_EXPORT static void Log(const param_type& p, std::string* l);
};
-#endif
template <>
struct IPC_EXPORT ParamTraits<std::vector<char> > {
@@ -316,7 +299,7 @@ struct ParamTraits<std::vector<P> > {
param_type* r) {
int size;
// ReadLength() checks for < 0 itself.
- if (!m->ReadLength(iter, &size))
+ if (!iter->ReadLength(&size))
return false;
// Resizing beforehand is not safe, see BUG 1006367 for details.
if (INT_MAX / sizeof(P) <= static_cast<size_t>(size))
@@ -349,7 +332,7 @@ struct ParamTraits<std::set<P> > {
static bool Read(const Message* m, PickleIterator* iter,
param_type* r) {
int size;
- if (!m->ReadLength(iter, &size))
+ if (!iter->ReadLength(&size))
return false;
for (int i = 0; i < size; ++i) {
P item;
@@ -520,8 +503,8 @@ struct IPC_EXPORT ParamTraits<base::TimeTicks> {
};
template <>
-struct ParamTraits<Tuple0> {
- typedef Tuple0 param_type;
+struct ParamTraits<Tuple<>> {
+ typedef Tuple<> param_type;
static void Write(Message* m, const param_type& p) {
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
@@ -532,112 +515,112 @@ struct ParamTraits<Tuple0> {
};
template <class A>
-struct ParamTraits< Tuple1<A> > {
- typedef Tuple1<A> param_type;
+struct ParamTraits<Tuple<A>> {
+ typedef Tuple<A> param_type;
static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.a);
+ WriteParam(m, get<0>(p));
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return ReadParam(m, iter, &r->a);
+ return ReadParam(m, iter, &get<0>(*r));
}
static void Log(const param_type& p, std::string* l) {
- LogParam(p.a, l);
+ LogParam(get<0>(p), l);
}
};
template <class A, class B>
-struct ParamTraits< Tuple2<A, B> > {
- typedef Tuple2<A, B> param_type;
+struct ParamTraits< Tuple<A, B> > {
+ typedef Tuple<A, B> param_type;
static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.a);
- WriteParam(m, p.b);
+ WriteParam(m, get<0>(p));
+ WriteParam(m, get<1>(p));
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return (ReadParam(m, iter, &r->a) &&
- ReadParam(m, iter, &r->b));
+ return (ReadParam(m, iter, &get<0>(*r)) &&
+ ReadParam(m, iter, &get<1>(*r)));
}
static void Log(const param_type& p, std::string* l) {
- LogParam(p.a, l);
+ LogParam(get<0>(p), l);
l->append(", ");
- LogParam(p.b, l);
+ LogParam(get<1>(p), l);
}
};
template <class A, class B, class C>
-struct ParamTraits< Tuple3<A, B, C> > {
- typedef Tuple3<A, B, C> param_type;
+struct ParamTraits< Tuple<A, B, C> > {
+ typedef Tuple<A, B, C> param_type;
static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.a);
- WriteParam(m, p.b);
- WriteParam(m, p.c);
+ WriteParam(m, get<0>(p));
+ WriteParam(m, get<1>(p));
+ WriteParam(m, get<2>(p));
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return (ReadParam(m, iter, &r->a) &&
- ReadParam(m, iter, &r->b) &&
- ReadParam(m, iter, &r->c));
+ return (ReadParam(m, iter, &get<0>(*r)) &&
+ ReadParam(m, iter, &get<1>(*r)) &&
+ ReadParam(m, iter, &get<2>(*r)));
}
static void Log(const param_type& p, std::string* l) {
- LogParam(p.a, l);
+ LogParam(get<0>(p), l);
l->append(", ");
- LogParam(p.b, l);
+ LogParam(get<1>(p), l);
l->append(", ");
- LogParam(p.c, l);
+ LogParam(get<2>(p), l);
}
};
template <class A, class B, class C, class D>
-struct ParamTraits< Tuple4<A, B, C, D> > {
- typedef Tuple4<A, B, C, D> param_type;
+struct ParamTraits< Tuple<A, B, C, D> > {
+ typedef Tuple<A, B, C, D> param_type;
static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.a);
- WriteParam(m, p.b);
- WriteParam(m, p.c);
- WriteParam(m, p.d);
+ WriteParam(m, get<0>(p));
+ WriteParam(m, get<1>(p));
+ WriteParam(m, get<2>(p));
+ WriteParam(m, get<3>(p));
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return (ReadParam(m, iter, &r->a) &&
- ReadParam(m, iter, &r->b) &&
- ReadParam(m, iter, &r->c) &&
- ReadParam(m, iter, &r->d));
+ return (ReadParam(m, iter, &get<0>(*r)) &&
+ ReadParam(m, iter, &get<1>(*r)) &&
+ ReadParam(m, iter, &get<2>(*r)) &&
+ ReadParam(m, iter, &get<3>(*r)));
}
static void Log(const param_type& p, std::string* l) {
- LogParam(p.a, l);
+ LogParam(get<0>(p), l);
l->append(", ");
- LogParam(p.b, l);
+ LogParam(get<1>(p), l);
l->append(", ");
- LogParam(p.c, l);
+ LogParam(get<2>(p), l);
l->append(", ");
- LogParam(p.d, l);
+ LogParam(get<3>(p), l);
}
};
template <class A, class B, class C, class D, class E>
-struct ParamTraits< Tuple5<A, B, C, D, E> > {
- typedef Tuple5<A, B, C, D, E> param_type;
+struct ParamTraits< Tuple<A, B, C, D, E> > {
+ typedef Tuple<A, B, C, D, E> param_type;
static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.a);
- WriteParam(m, p.b);
- WriteParam(m, p.c);
- WriteParam(m, p.d);
- WriteParam(m, p.e);
+ WriteParam(m, get<0>(p));
+ WriteParam(m, get<1>(p));
+ WriteParam(m, get<2>(p));
+ WriteParam(m, get<3>(p));
+ WriteParam(m, get<4>(p));
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
- return (ReadParam(m, iter, &r->a) &&
- ReadParam(m, iter, &r->b) &&
- ReadParam(m, iter, &r->c) &&
- ReadParam(m, iter, &r->d) &&
- ReadParam(m, iter, &r->e));
+ return (ReadParam(m, iter, &get<0>(*r)) &&
+ ReadParam(m, iter, &get<1>(*r)) &&
+ ReadParam(m, iter, &get<2>(*r)) &&
+ ReadParam(m, iter, &get<3>(*r)) &&
+ ReadParam(m, iter, &get<4>(*r)));
}
static void Log(const param_type& p, std::string* l) {
- LogParam(p.a, l);
+ LogParam(get<0>(p), l);
l->append(", ");
- LogParam(p.b, l);
+ LogParam(get<1>(p), l);
l->append(", ");
- LogParam(p.c, l);
+ LogParam(get<2>(p), l);
l->append(", ");
- LogParam(p.d, l);
+ LogParam(get<3>(p), l);
l->append(", ");
- LogParam(p.e, l);
+ LogParam(get<4>(p), l);
}
};
@@ -651,7 +634,7 @@ struct ParamTraits<ScopedVector<P> > {
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
int size = 0;
- if (!m->ReadLength(iter, &size))
+ if (!iter->ReadLength(&size))
return false;
if (INT_MAX/sizeof(P) <= static_cast<size_t>(size))
return false;
@@ -690,7 +673,7 @@ struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > {
}
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
int size;
- if (!m->ReadLength(iter, &size))
+ if (!iter->ReadLength(&size))
return false;
for (int i = 0; i < size; ++i) {
K key;
@@ -865,7 +848,8 @@ class ParamDeserializer : public MessageReplyDeserializer {
public:
explicit ParamDeserializer(const RefTuple& out) : out_(out) { }
- bool SerializeOutputParameters(const IPC::Message& msg, PickleIterator iter) {
+ bool SerializeOutputParameters(const IPC::Message& msg,
+ PickleIterator iter) override {
return ReadParam(&msg, &iter, &out_);
}
@@ -911,7 +895,7 @@ class SyncMessageSchema {
Method func) {
Message* reply = SyncMessage::GenerateReply(msg);
if (ok) {
- Tuple1<Message&> t = MakeRefTuple(*reply);
+ Tuple<Message&> t = MakeRefTuple(*reply);
ConnectMessageAndReply(msg, reply);
DispatchToMethod(obj, func, send_params, &t);
} else {
@@ -922,33 +906,9 @@ class SyncMessageSchema {
return ok;
}
- template<typename TA>
- static void WriteReplyParams(Message* reply, TA a) {
- ReplyParam p(a);
- WriteParam(reply, p);
- }
-
- template<typename TA, typename TB>
- static void WriteReplyParams(Message* reply, TA a, TB b) {
- ReplyParam p(a, b);
- WriteParam(reply, p);
- }
-
- template<typename TA, typename TB, typename TC>
- static void WriteReplyParams(Message* reply, TA a, TB b, TC c) {
- ReplyParam p(a, b, c);
- WriteParam(reply, p);
- }
-
- template<typename TA, typename TB, typename TC, typename TD>
- static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) {
- ReplyParam p(a, b, c, d);
- WriteParam(reply, p);
- }
-
- 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) {
- ReplyParam p(a, b, c, d, e);
+ template <typename... Ts>
+ static void WriteReplyParams(Message* reply, Ts... args) {
+ ReplyParam p(args...);
WriteParam(reply, p);
}
};
diff --git a/chromium/ipc/ipc_nacl.gyp b/chromium/ipc/ipc_nacl.gyp
index 6f0d522d562..5faf9af1f4c 100644
--- a/chromium/ipc/ipc_nacl.gyp
+++ b/chromium/ipc/ipc_nacl.gyp
@@ -26,7 +26,6 @@
},
'dependencies': [
'../base/base_nacl.gyp:base_nacl',
- '../native_client/tools.gyp:prep_toolchain',
],
},
{
@@ -56,7 +55,6 @@
],
'dependencies': [
'../base/base_nacl.gyp:base_nacl_nonsfi',
- '../native_client/tools.gyp:prep_toolchain',
],
},
],
diff --git a/chromium/ipc/ipc_perftest_support.cc b/chromium/ipc/ipc_perftest_support.cc
index d0cbe5ef803..ae8be7fb2d1 100644
--- a/chromium/ipc/ipc_perftest_support.cc
+++ b/chromium/ipc/ipc_perftest_support.cc
@@ -26,6 +26,10 @@
namespace IPC {
namespace test {
+// Avoid core 0 due to conflicts with Intel's Power Gadget.
+// Setting thread affinity will fail harmlessly on single/dual core machines.
+const int kSharedCore = 2;
+
// This class simply collects stats about abstract "events" (each of which has a
// start time and an end time).
class EventTimeTracker {
@@ -99,8 +103,8 @@ class ChannelReflectorListener : public Listener {
EXPECT_TRUE(iter.ReadInt64(&time_internal));
int msgid;
EXPECT_TRUE(iter.ReadInt(&msgid));
- std::string payload;
- EXPECT_TRUE(iter.ReadString(&payload));
+ base::StringPiece payload;
+ EXPECT_TRUE(iter.ReadStringPiece(&payload));
// Include message deserialization in latency.
base::TimeTicks now = base::TimeTicks::Now();
@@ -229,7 +233,7 @@ IPCChannelPerfTestBase::GetDefaultTestParams() {
list.push_back(PingPongTestParams(144, 50000));
list.push_back(PingPongTestParams(1728, 50000));
list.push_back(PingPongTestParams(20736, 12000));
- list.push_back(PingPongTestParams(248832, 100));
+ list.push_back(PingPongTestParams(248832, 1000));
return list;
}
@@ -244,6 +248,7 @@ void IPCChannelPerfTestBase::RunTestChannelPingPong(
ASSERT_TRUE(ConnectChannel());
ASSERT_TRUE(StartClient());
+ LockThreadAffinity thread_locker(kSharedCore);
for (size_t i = 0; i < params.size(); i++) {
listener.SetTestParams(params[i].message_count(),
params[i].message_size());
@@ -284,6 +289,7 @@ void IPCChannelPerfTestBase::RunTestChannelProxyPingPong(
listener.Init(channel_proxy());
ASSERT_TRUE(StartClient());
+ LockThreadAffinity thread_locker(kSharedCore);
for (size_t i = 0; i < params.size(); i++) {
listener.SetTestParams(params[i].message_count(),
params[i].message_size());
@@ -326,6 +332,7 @@ scoped_ptr<Channel> PingPongTestClient::CreateChannel(
}
int PingPongTestClient::RunMain() {
+ LockThreadAffinity thread_locker(kSharedCore);
scoped_ptr<Channel> channel = CreateChannel(listener_.get());
listener_->Init(channel.get());
CHECK(channel->Connect());
@@ -335,7 +342,39 @@ int PingPongTestClient::RunMain() {
}
scoped_refptr<base::TaskRunner> PingPongTestClient::task_runner() {
- return main_message_loop_.message_loop_proxy();
+ return main_message_loop_.task_runner();
+}
+
+LockThreadAffinity::LockThreadAffinity(int cpu_number)
+ : affinity_set_ok_(false) {
+#if defined(OS_WIN)
+ const DWORD_PTR thread_mask = 1 << cpu_number;
+ old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask);
+ affinity_set_ok_ = old_affinity_ != 0;
+#elif defined(OS_LINUX)
+ cpu_set_t cpuset;
+ CPU_ZERO(&cpuset);
+ CPU_SET(cpu_number, &cpuset);
+ auto get_result = sched_getaffinity(0, sizeof(old_cpuset_), &old_cpuset_);
+ DCHECK_EQ(0, get_result);
+ auto set_result = sched_setaffinity(0, sizeof(cpuset), &cpuset);
+ // Check for get_result failure, even though it should always succeed.
+ affinity_set_ok_ = (set_result == 0) && (get_result == 0);
+#endif
+ if (!affinity_set_ok_)
+ LOG(WARNING) << "Failed to set thread affinity to CPU " << cpu_number;
+}
+
+LockThreadAffinity::~LockThreadAffinity() {
+ if (!affinity_set_ok_)
+ return;
+#if defined(OS_WIN)
+ auto set_result = SetThreadAffinityMask(GetCurrentThread(), old_affinity_);
+ DCHECK_NE(0u, set_result);
+#elif defined(OS_LINUX)
+ auto set_result = sched_setaffinity(0, sizeof(old_cpuset_), &old_cpuset_);
+ DCHECK_EQ(0, set_result);
+#endif
}
} // namespace test
diff --git a/chromium/ipc/ipc_perftest_support.h b/chromium/ipc/ipc_perftest_support.h
index 611a2096330..578256f8b11 100644
--- a/chromium/ipc/ipc_perftest_support.h
+++ b/chromium/ipc/ipc_perftest_support.h
@@ -53,6 +53,27 @@ class PingPongTestClient {
scoped_ptr<Channel> channel_;
};
+// This class locks the current thread to a particular CPU core. This is
+// important because otherwise the different threads and processes of these
+// tests end up on different CPU cores which means that all of the cores are
+// lightly loaded so the OS (Windows and Linux) fails to ramp up the CPU
+// frequency, leading to unpredictable and often poor performance.
+class LockThreadAffinity {
+ public:
+ explicit LockThreadAffinity(int cpu_number);
+ ~LockThreadAffinity();
+
+ private:
+ bool affinity_set_ok_;
+#if defined(OS_WIN)
+ DWORD_PTR old_affinity_;
+#elif defined(OS_LINUX)
+ cpu_set_t old_cpuset_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(LockThreadAffinity);
+};
+
}
}
diff --git a/chromium/ipc/ipc_platform_file_attachment_posix.cc b/chromium/ipc/ipc_platform_file_attachment_posix.cc
new file mode 100644
index 00000000000..b704750c156
--- /dev/null
+++ b/chromium/ipc/ipc_platform_file_attachment_posix.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 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/ipc_platform_file_attachment_posix.h"
+
+namespace IPC {
+namespace internal {
+
+PlatformFileAttachment::PlatformFileAttachment(base::PlatformFile file)
+ : file_(file) {
+}
+
+PlatformFileAttachment::PlatformFileAttachment(base::ScopedFD file)
+ : file_(file.get()), owning_(file.Pass()) {
+}
+
+PlatformFileAttachment::~PlatformFileAttachment() {
+}
+
+MessageAttachment::Type PlatformFileAttachment::GetType() const {
+ return TYPE_PLATFORM_FILE;
+}
+
+base::PlatformFile PlatformFileAttachment::TakePlatformFile() {
+ ignore_result(owning_.release());
+ return file_;
+}
+
+base::PlatformFile GetPlatformFile(
+ scoped_refptr<MessageAttachment> attachment) {
+ DCHECK_EQ(attachment->GetType(), MessageAttachment::TYPE_PLATFORM_FILE);
+ return static_cast<PlatformFileAttachment*>(attachment.get())->file();
+}
+
+} // namespace internal
+} // namespace IPC
diff --git a/chromium/ipc/ipc_platform_file_attachment_posix.h b/chromium/ipc/ipc_platform_file_attachment_posix.h
new file mode 100644
index 00000000000..d1eff609c53
--- /dev/null
+++ b/chromium/ipc/ipc_platform_file_attachment_posix.h
@@ -0,0 +1,43 @@
+// Copyright (c) 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_PLATFORM_FILE_ATTACHMENT_H_
+#define IPC_IPC_PLATFORM_FILE_ATTACHMENT_H_
+
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_message_attachment.h"
+
+namespace IPC {
+namespace internal {
+
+// A platform file that is sent over |Channel| as a part of |Message|.
+// PlatformFileAttachment optionally owns the file and |owning_| is set in that
+// case. Also, |file_| is not cleared even after the ownership is taken.
+// Some old clients require this strange behavior.
+class IPC_EXPORT PlatformFileAttachment : public MessageAttachment {
+ public:
+ // Non-owning constructor
+ explicit PlatformFileAttachment(base::PlatformFile file);
+ // Owning constructor
+ explicit PlatformFileAttachment(base::ScopedFD file);
+
+ Type GetType() const override;
+ base::PlatformFile TakePlatformFile() override;
+
+ base::PlatformFile file() const { return file_; }
+ bool Owns() const { return owning_.is_valid(); }
+
+ private:
+ ~PlatformFileAttachment() override;
+
+ base::PlatformFile file_;
+ base::ScopedFD owning_;
+};
+
+base::PlatformFile GetPlatformFile(scoped_refptr<MessageAttachment> attachment);
+
+} // namespace internal
+} // namespace IPC
+
+#endif // IPC_IPC_PLATFORM_FILE_ATTACHMENT_H_
diff --git a/chromium/ipc/ipc_security_test_util.cc b/chromium/ipc/ipc_security_test_util.cc
new file mode 100644
index 00000000000..4ae5a06096d
--- /dev/null
+++ b/chromium/ipc/ipc_security_test_util.cc
@@ -0,0 +1,25 @@
+// 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.
+
+#include "ipc/ipc_security_test_util.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/run_loop.h"
+#include "ipc/ipc_channel_proxy.h"
+
+namespace IPC {
+
+void IpcSecurityTestUtil::PwnMessageReceived(ChannelProxy* channel,
+ const IPC::Message& message) {
+ base::RunLoop run_loop;
+ base::Closure inject_message = base::Bind(
+ base::IgnoreResult(&IPC::ChannelProxy::Context::OnMessageReceived),
+ channel->context(), message);
+ channel->context()->ipc_task_runner()->PostTaskAndReply(
+ FROM_HERE, inject_message, run_loop.QuitClosure());
+ run_loop.Run();
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/ipc_security_test_util.h b/chromium/ipc/ipc_security_test_util.h
new file mode 100644
index 00000000000..1ec2555fce7
--- /dev/null
+++ b/chromium/ipc/ipc_security_test_util.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef IPC_IPC_SECURITY_TEST_UTIL_H_
+#define IPC_IPC_SECURITY_TEST_UTIL_H_
+
+#include "base/basictypes.h"
+
+namespace IPC {
+
+class ChannelProxy;
+class Message;
+
+class IpcSecurityTestUtil {
+ public:
+ // Enables testing of security exploit scenarios where a compromised child
+ // process can send a malicious message of an arbitrary type.
+ //
+ // This function will post the message to the IPC channel's thread, where it
+ // is offered to the channel's listeners. Afterwards, a reply task is posted
+ // back to the current thread. This function blocks until the reply task is
+ // received. For messages forwarded back to the current thread, we won't
+ // return until after the message has been handled here.
+ //
+ // Use this only for testing security bugs in a browsertest; other uses are
+ // likely perilous. Unit tests should be using IPC::TestSink which has an
+ // OnMessageReceived method you can call directly. Non-security browsertests
+ // should just exercise the child process's normal codepaths to send messages.
+ static void PwnMessageReceived(ChannelProxy* channel, const Message& message);
+
+ private:
+ IpcSecurityTestUtil(); // Not instantiable.
+
+ DISALLOW_COPY_AND_ASSIGN(IpcSecurityTestUtil);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_SECURITY_TEST_UTIL_H_
diff --git a/chromium/ipc/ipc_send_fds_test.cc b/chromium/ipc/ipc_send_fds_test.cc
index cf2c68003de..148eecab125 100644
--- a/chromium/ipc/ipc_send_fds_test.cc
+++ b/chromium/ipc/ipc_send_fds_test.cc
@@ -19,28 +19,40 @@ extern "C" {
#include "base/callback.h"
#include "base/file_descriptor_posix.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
+#include "ipc/ipc_message_attachment_set.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_test_base.h"
+#if defined(OS_POSIX)
+#include "base/macros.h"
+#endif
+
namespace {
-const unsigned kNumFDsToSend = 20;
+const unsigned kNumFDsToSend = 7; // per message
+const unsigned kNumMessages = 20;
const char* kDevZeroPath = "/dev/zero";
+#if defined(OS_POSIX)
+static_assert(kNumFDsToSend ==
+ IPC::MessageAttachmentSet::kMaxDescriptorsPerMessage,
+ "The number of FDs to send must be kMaxDescriptorsPerMessage.");
+#endif
+
class MyChannelDescriptorListenerBase : public IPC::Listener {
public:
bool OnMessageReceived(const IPC::Message& message) override {
PickleIterator iter(message);
-
base::FileDescriptor descriptor;
-
- IPC::ParamTraits<base::FileDescriptor>::Read(&message, &iter, &descriptor);
-
- HandleFD(descriptor.fd);
+ while (IPC::ParamTraits<base::FileDescriptor>::Read(
+ &message, &iter, &descriptor)) {
+ HandleFD(descriptor.fd);
+ }
return true;
}
@@ -57,7 +69,7 @@ class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase {
}
bool GotExpectedNumberOfDescriptors() const {
- return num_fds_received_ == kNumFDsToSend;
+ return num_fds_received_ == kNumFDsToSend * kNumMessages;
}
void OnChannelError() override {
@@ -66,6 +78,7 @@ class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase {
protected:
void HandleFD(int fd) override {
+ ASSERT_GE(fd, 0);
// Check that we can read from the FD.
char buf;
ssize_t amt_read = read(fd, &buf, 1);
@@ -82,7 +95,7 @@ class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase {
ASSERT_EQ(expected_inode_num_, st.st_ino);
++num_fds_received_;
- if (num_fds_received_ == kNumFDsToSend)
+ if (num_fds_received_ == kNumFDsToSend * kNumMessages)
base::MessageLoop::current()->Quit();
}
@@ -101,14 +114,15 @@ class IPCSendFdsTest : public IPCTestBase {
ASSERT_TRUE(ConnectChannel());
ASSERT_TRUE(StartClient());
- for (unsigned i = 0; i < kNumFDsToSend; ++i) {
- const int fd = open(kDevZeroPath, O_RDONLY);
- ASSERT_GE(fd, 0);
- base::FileDescriptor descriptor(fd, true);
-
+ for (unsigned i = 0; i < kNumMessages; ++i) {
IPC::Message* message =
new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL);
- IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
+ for (unsigned j = 0; j < kNumFDsToSend; ++j) {
+ const int fd = open(kDevZeroPath, O_RDONLY);
+ ASSERT_GE(fd, 0);
+ base::FileDescriptor descriptor(fd, true);
+ IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
+ }
ASSERT_TRUE(sender()->Send(message));
}
@@ -237,12 +251,10 @@ class PipeChannelHelper {
out = IPC::Channel::CreateClient(out_handle, &cb_listener_);
// PostTask the connect calls to make sure the callbacks happens
// on the right threads.
- in_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&PipeChannelHelper::Connect, in.get()));
- out_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&PipeChannelHelper::Connect, out.get()));
+ in_thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&PipeChannelHelper::Connect, in.get()));
+ out_thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&PipeChannelHelper::Connect, out.get()));
}
static void DestroyChannel(scoped_ptr<IPC::Channel> *c,
@@ -254,12 +266,10 @@ class PipeChannelHelper {
~PipeChannelHelper() {
base::WaitableEvent a(true, false);
base::WaitableEvent b(true, false);
- in_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&PipeChannelHelper::DestroyChannel, &in, &a));
- out_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&PipeChannelHelper::DestroyChannel, &out, &b));
+ in_thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&PipeChannelHelper::DestroyChannel, &in, &a));
+ out_thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&PipeChannelHelper::DestroyChannel, &out, &b));
a.Wait();
b.Wait();
}
@@ -308,11 +318,9 @@ class IPCMultiSendingFdsTest : public testing::Test {
for (int i = 0; i < pipes_to_send; i++) {
received_.Reset();
std::pair<int, int> pipe_fds = make_socket_pair();
- t->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&PipeChannelHelper::Send,
- base::Unretained(dest),
- pipe_fds.second));
+ t->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&PipeChannelHelper::Send,
+ base::Unretained(dest), pipe_fds.second));
char tmp = 'x';
CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds.first, &tmp, 1)));
CHECK_EQ(0, IGNORE_EINTR(close(pipe_fds.first)));
diff --git a/chromium/ipc/ipc_sync_channel.cc b/chromium/ipc/ipc_sync_channel.cc
index a6ef27ada67..06cd46f1ea6 100644
--- a/chromium/ipc/ipc_sync_channel.cc
+++ b/chromium/ipc/ipc_sync_channel.cc
@@ -5,7 +5,6 @@
#include "ipc/ipc_sync_channel.h"
#include "base/bind.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
@@ -13,6 +12,7 @@
#include "base/synchronization/waitable_event_watcher.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_local.h"
+#include "base/trace_event/trace_event.h"
#include "ipc/ipc_channel_factory.h"
#include "ipc/ipc_logging.h"
#include "ipc/ipc_message_macros.h"
diff --git a/chromium/ipc/ipc_sync_channel_unittest.cc b/chromium/ipc/ipc_sync_channel_unittest.cc
index f834ec3b5bb..7e81d5deabc 100644
--- a/chromium/ipc/ipc_sync_channel_unittest.cc
+++ b/chromium/ipc/ipc_sync_channel_unittest.cc
@@ -9,13 +9,15 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/process/process_handle.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
#include "ipc/ipc_listener.h"
@@ -72,7 +74,7 @@ class Worker : public Listener, public Sender {
}
void Start() {
StartThread(&listener_thread_, base::MessageLoop::TYPE_DEFAULT);
- ListenerThread()->message_loop()->PostTask(
+ ListenerThread()->task_runner()->PostTask(
FROM_HERE, base::Bind(&Worker::OnStart, this));
}
void Shutdown() {
@@ -80,7 +82,7 @@ class Worker : public Listener, public Sender {
// ~Worker(), since that'll reset the vtable pointer (to Worker's), which
// may result in a race conditions. See http://crbug.com/25841.
WaitableEvent listener_done(false, false), ipc_done(false, false);
- ListenerThread()->message_loop()->PostTask(
+ ListenerThread()->task_runner()->PostTask(
FROM_HERE, base::Bind(&Worker::OnListenerThreadShutdown1, this,
&listener_done, &ipc_done));
listener_done.Wait();
@@ -124,7 +126,7 @@ class Worker : public Listener, public Sender {
protected:
SyncChannel* channel() { return channel_.get(); }
- // Functions for dervied classes to implement if they wish.
+ // Functions for derived classes to implement if they wish.
virtual void Run() { }
virtual void OnAnswer(int* answer) { NOTREACHED(); }
virtual void OnAnswerDelay(Message* reply_msg) {
@@ -152,8 +154,8 @@ class Worker : public Listener, public Sender {
virtual SyncChannel* CreateChannel() {
scoped_ptr<SyncChannel> channel = SyncChannel::Create(
- channel_name_, mode_, this, ipc_thread_.message_loop_proxy().get(),
- true, &shutdown_event_);
+ channel_name_, mode_, this, ipc_thread_.task_runner().get(), true,
+ &shutdown_event_);
return channel.release();
}
@@ -190,9 +192,9 @@ class Worker : public Listener, public Sender {
base::RunLoop().RunUntilIdle();
ipc_event->Signal();
- listener_thread_.message_loop()->PostTask(
- FROM_HERE, base::Bind(&Worker::OnListenerThreadShutdown2, this,
- listener_event));
+ listener_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&Worker::OnListenerThreadShutdown2, this, listener_event));
}
void OnListenerThreadShutdown2(WaitableEvent* listener_event) {
@@ -324,8 +326,7 @@ class TwoStepServer : public Worker {
SyncChannel* CreateChannel() override {
SyncChannel* channel =
SyncChannel::Create(channel_name(), mode(), this,
- ipc_thread().message_loop_proxy().get(),
- create_pipe_now_,
+ ipc_thread().task_runner().get(), create_pipe_now_,
shutdown_event()).release();
return channel;
}
@@ -347,8 +348,7 @@ class TwoStepClient : public Worker {
SyncChannel* CreateChannel() override {
SyncChannel* channel =
SyncChannel::Create(channel_name(), mode(), this,
- ipc_thread().message_loop_proxy().get(),
- create_pipe_now_,
+ ipc_thread().task_runner().get(), create_pipe_now_,
shutdown_event()).release();
return channel;
}
@@ -896,11 +896,10 @@ class DoneEventRaceServer : public Worker {
: Worker(Channel::MODE_SERVER, "done_event_race_server") { }
void Run() override {
- base::MessageLoop::current()->PostTask(FROM_HERE,
- base::Bind(&NestedCallback, this));
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&TimeoutCallback),
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&NestedCallback, this));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&TimeoutCallback),
base::TimeDelta::FromSeconds(9));
// Even though we have a timeout on the Send, it will succeed since for this
// bug, the reply message comes back and is deserialized, however the done
@@ -926,17 +925,17 @@ TEST_F(IPCSyncChannelTest, DoneEventRace) {
class TestSyncMessageFilter : public SyncMessageFilter {
public:
- TestSyncMessageFilter(base::WaitableEvent* shutdown_event,
- Worker* worker,
- scoped_refptr<base::MessageLoopProxy> message_loop)
+ TestSyncMessageFilter(
+ base::WaitableEvent* shutdown_event,
+ Worker* worker,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: SyncMessageFilter(shutdown_event),
worker_(worker),
- message_loop_(message_loop) {
- }
+ task_runner_(task_runner) {}
void OnFilterAdded(Sender* sender) override {
SyncMessageFilter::OnFilterAdded(sender);
- message_loop_->PostTask(
+ task_runner_->PostTask(
FROM_HERE,
base::Bind(&TestSyncMessageFilter::SendMessageOnHelperThread, this));
}
@@ -954,7 +953,7 @@ class TestSyncMessageFilter : public SyncMessageFilter {
~TestSyncMessageFilter() override {}
Worker* worker_;
- scoped_refptr<base::MessageLoopProxy> message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
class SyncMessageFilterServer : public Worker {
@@ -966,7 +965,7 @@ class SyncMessageFilterServer : public Worker {
options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
thread_.StartWithOptions(options);
filter_ = new TestSyncMessageFilter(shutdown_event(), this,
- thread_.message_loop_proxy());
+ thread_.task_runner());
}
void Run() override {
@@ -987,7 +986,7 @@ class ServerSendAfterClose : public Worker {
}
bool SendDummy() {
- ListenerThread()->message_loop()->PostTask(
+ ListenerThread()->task_runner()->PostTask(
FROM_HERE, base::Bind(base::IgnoreResult(&ServerSendAfterClose::Send),
this, new SyncChannelTestMsg_NoArgs));
return true;
@@ -1053,7 +1052,7 @@ class RestrictedDispatchServer : public Worker {
Send(msg);
// Signal the event after the message has been sent on the channel, on the
// IPC thread.
- ipc_thread().message_loop()->PostTask(
+ ipc_thread().task_runner()->PostTask(
FROM_HERE, base::Bind(&RestrictedDispatchServer::OnPingSent, this));
}
@@ -1128,7 +1127,7 @@ class RestrictedDispatchClient : public Worker {
// send a message on that same channel.
channel()->SetRestrictDispatchChannelGroup(1);
- server_->ListenerThread()->message_loop()->PostTask(
+ server_->ListenerThread()->task_runner()->PostTask(
FROM_HERE, base::Bind(&RestrictedDispatchServer::OnDoPing, server_, 1));
sent_ping_event_->Wait();
Send(new SyncChannelTestMsg_NoArgs);
@@ -1137,15 +1136,11 @@ class RestrictedDispatchClient : public Worker {
else
LOG(ERROR) << "Send failed to dispatch incoming message on same channel";
- non_restricted_channel_ =
- SyncChannel::Create("non_restricted_channel",
- IPC::Channel::MODE_CLIENT,
- this,
- ipc_thread().message_loop_proxy().get(),
- true,
- shutdown_event());
+ non_restricted_channel_ = SyncChannel::Create(
+ "non_restricted_channel", IPC::Channel::MODE_CLIENT, this,
+ ipc_thread().task_runner().get(), true, shutdown_event());
- server_->ListenerThread()->message_loop()->PostTask(
+ server_->ListenerThread()->task_runner()->PostTask(
FROM_HERE, base::Bind(&RestrictedDispatchServer::OnDoPing, server_, 2));
sent_ping_event_->Wait();
// Check that the incoming message is *not* dispatched when sending on the
@@ -1170,7 +1165,7 @@ class RestrictedDispatchClient : public Worker {
// Check that the incoming message on the non-restricted channel is
// dispatched when sending on the restricted channel.
- server2_->ListenerThread()->message_loop()->PostTask(
+ server2_->ListenerThread()->task_runner()->PostTask(
FROM_HERE,
base::Bind(&NonRestrictedDispatchServer::OnDoPingTTL, server2_, 3));
int value = 0;
@@ -1392,10 +1387,10 @@ class RestrictedDispatchDeadlockClient1 : public Worker {
void Run() override {
server_ready_event_->Wait();
- server_->ListenerThread()->message_loop()->PostTask(
+ server_->ListenerThread()->task_runner()->PostTask(
FROM_HERE,
base::Bind(&RestrictedDispatchDeadlockServer::OnDoServerTask, server_));
- peer_->ListenerThread()->message_loop()->PostTask(
+ peer_->ListenerThread()->task_runner()->PostTask(
FROM_HERE,
base::Bind(&RestrictedDispatchDeadlockClient2::OnDoClient2Task, peer_));
events_[0]->Wait();
@@ -1528,13 +1523,9 @@ class RestrictedDispatchPipeWorker : public Worker {
if (is_first())
event1_->Signal();
event2_->Wait();
- other_channel_ =
- SyncChannel::Create(other_channel_name_,
- IPC::Channel::MODE_CLIENT,
- this,
- ipc_thread().message_loop_proxy().get(),
- true,
- shutdown_event());
+ other_channel_ = SyncChannel::Create(
+ other_channel_name_, IPC::Channel::MODE_CLIENT, this,
+ ipc_thread().task_runner().get(), true, shutdown_event());
other_channel_->SetRestrictDispatchChannelGroup(group_);
if (!is_first()) {
event1_->Signal();
@@ -1608,13 +1599,9 @@ class ReentrantReplyServer1 : public Worker {
server_ready_(server_ready) { }
void Run() override {
- server2_channel_ =
- SyncChannel::Create("reentrant_reply2",
- IPC::Channel::MODE_CLIENT,
- this,
- ipc_thread().message_loop_proxy().get(),
- true,
- shutdown_event());
+ server2_channel_ = SyncChannel::Create(
+ "reentrant_reply2", IPC::Channel::MODE_CLIENT, this,
+ ipc_thread().task_runner().get(), true, shutdown_event());
server_ready_->Signal();
Message* msg = new SyncChannelTestMsg_Reentrant1();
server2_channel_->Send(msg);
diff --git a/chromium/ipc/ipc_sync_message.cc b/chromium/ipc/ipc_sync_message.cc
index 9e3acf8e1fa..fd6dc471d59 100644
--- a/chromium/ipc/ipc_sync_message.cc
+++ b/chromium/ipc/ipc_sync_message.cc
@@ -113,7 +113,7 @@ bool SyncMessage::ReadSyncHeader(const Message& msg, SyncHeader* header) {
DCHECK(msg.is_sync() || msg.is_reply());
PickleIterator iter(msg);
- bool result = msg.ReadInt(&iter, &header->message_id);
+ bool result = iter.ReadInt(&header->message_id);
if (!result) {
NOTREACHED();
return false;
diff --git a/chromium/ipc/ipc_sync_message_filter.cc b/chromium/ipc/ipc_sync_message_filter.cc
index e2ea1bfb1ee..6a408ec12cf 100644
--- a/chromium/ipc/ipc_sync_message_filter.cc
+++ b/chromium/ipc/ipc_sync_message_filter.cc
@@ -7,33 +7,33 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_sync_message.h"
-using base::MessageLoopProxy;
-
namespace IPC {
SyncMessageFilter::SyncMessageFilter(base::WaitableEvent* shutdown_event)
: sender_(NULL),
- listener_loop_(MessageLoopProxy::current()),
+ listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
shutdown_event_(shutdown_event) {
}
bool SyncMessageFilter::Send(Message* message) {
{
base::AutoLock auto_lock(lock_);
- if (!io_loop_.get()) {
+ if (!io_task_runner_.get()) {
delete message;
return false;
}
}
if (!message->is_sync()) {
- io_loop_->PostTask(
- FROM_HERE, base::Bind(&SyncMessageFilter::SendOnIOThread, this, message));
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&SyncMessageFilter::SendOnIOThread, this, message));
return true;
}
@@ -47,12 +47,14 @@ bool SyncMessageFilter::Send(Message* message) {
base::AutoLock auto_lock(lock_);
// Can't use this class on the main thread or else it can lead to deadlocks.
// Also by definition, can't use this on IO thread since we're blocking it.
- DCHECK(MessageLoopProxy::current().get() != listener_loop_.get());
- DCHECK(MessageLoopProxy::current().get() != io_loop_.get());
+ if (base::ThreadTaskRunnerHandle::IsSet()) {
+ DCHECK(base::ThreadTaskRunnerHandle::Get() != listener_task_runner_);
+ DCHECK(base::ThreadTaskRunnerHandle::Get() != io_task_runner_);
+ }
pending_sync_messages_.insert(&pending_message);
}
- io_loop_->PostTask(
+ io_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncMessageFilter::SendOnIOThread, this, message));
base::WaitableEvent* events[2] = { shutdown_event_, &done_event };
@@ -70,7 +72,7 @@ bool SyncMessageFilter::Send(Message* message) {
void SyncMessageFilter::OnFilterAdded(Sender* sender) {
sender_ = sender;
base::AutoLock auto_lock(lock_);
- io_loop_ = MessageLoopProxy::current();
+ io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
}
void SyncMessageFilter::OnChannelError() {
diff --git a/chromium/ipc/ipc_sync_message_filter.h b/chromium/ipc/ipc_sync_message_filter.h
index 49c3ca03171..ee6677ef310 100644
--- a/chromium/ipc/ipc_sync_message_filter.h
+++ b/chromium/ipc/ipc_sync_message_filter.h
@@ -15,7 +15,7 @@
#include "ipc/message_filter.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
class WaitableEvent;
}
@@ -51,10 +51,10 @@ class IPC_EXPORT SyncMessageFilter : public MessageFilter, public Sender {
Sender* sender_;
// The process's main thread.
- scoped_refptr<base::MessageLoopProxy> listener_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
// The message loop where the Channel lives.
- scoped_refptr<base::MessageLoopProxy> io_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
typedef std::set<PendingSyncMsg*> PendingSyncMessages;
PendingSyncMessages pending_sync_messages_;
diff --git a/chromium/ipc/ipc_test_base.cc b/chromium/ipc/ipc_test_base.cc
index ba4e71156af..0d662822691 100644
--- a/chromium/ipc/ipc_test_base.cc
+++ b/chromium/ipc/ipc_test_base.cc
@@ -4,6 +4,7 @@
#include "build/build_config.h"
+#include "base/single_thread_task_runner.h"
#include "ipc/ipc_test_base.h"
#include "base/command_line.h"
@@ -22,8 +23,7 @@ std::string IPCTestBase::GetChannelName(const std::string& test_client_name) {
return test_client_name + "__Channel";
}
-IPCTestBase::IPCTestBase()
- : client_process_(base::kNullProcessHandle) {
+IPCTestBase::IPCTestBase() {
}
IPCTestBase::~IPCTestBase() {
@@ -104,8 +104,8 @@ std::string IPCTestBase::GetTestMainName() const {
}
bool IPCTestBase::DidStartClient() {
- DCHECK_NE(base::kNullProcessHandle, client_process_);
- return client_process_ != base::kNullProcessHandle;
+ DCHECK(client_process_.IsValid());
+ return client_process_.IsValid();
}
#if defined(OS_POSIX)
@@ -117,7 +117,7 @@ bool IPCTestBase::StartClient() {
}
bool IPCTestBase::StartClientWithFD(int ipcfd) {
- DCHECK_EQ(client_process_, base::kNullProcessHandle);
+ DCHECK(!client_process_.IsValid());
base::FileHandleMappingVector fds_to_map;
if (ipcfd > -1)
@@ -133,7 +133,7 @@ bool IPCTestBase::StartClientWithFD(int ipcfd) {
#elif defined(OS_WIN)
bool IPCTestBase::StartClient() {
- DCHECK_EQ(client_process_, base::kNullProcessHandle);
+ DCHECK(!client_process_.IsValid());
client_process_ = SpawnChild(GetTestMainName());
return DidStartClient();
}
@@ -141,12 +141,12 @@ bool IPCTestBase::StartClient() {
#endif
bool IPCTestBase::WaitForClientShutdown() {
- DCHECK(client_process_ != base::kNullProcessHandle);
+ DCHECK(client_process_.IsValid());
- bool rv = base::WaitForSingleProcess(client_process_,
- base::TimeDelta::FromSeconds(5));
- base::CloseProcessHandle(client_process_);
- client_process_ = base::kNullProcessHandle;
+ int exit_code;
+ bool rv = client_process_.WaitForExitWithTimeout(
+ base::TimeDelta::FromSeconds(5), &exit_code);
+ client_process_.Close();
return rv;
}
@@ -154,12 +154,12 @@ IPC::ChannelHandle IPCTestBase::GetTestChannelHandle() {
return GetChannelName(test_client_name_);
}
-scoped_refptr<base::TaskRunner> IPCTestBase::task_runner() {
- return message_loop_->message_loop_proxy();
+scoped_refptr<base::SequencedTaskRunner> IPCTestBase::task_runner() {
+ return message_loop_->task_runner();
}
scoped_ptr<IPC::ChannelFactory> IPCTestBase::CreateChannelFactory(
const IPC::ChannelHandle& handle,
- base::TaskRunner* runner) {
+ base::SequencedTaskRunner* runner) {
return IPC::ChannelFactory::Create(handle, IPC::Channel::MODE_SERVER);
}
diff --git a/chromium/ipc/ipc_test_base.h b/chromium/ipc/ipc_test_base.h
index 89d53db58cd..2a45f7230ef 100644
--- a/chromium/ipc/ipc_test_base.h
+++ b/chromium/ipc/ipc_test_base.h
@@ -32,9 +32,9 @@ class IPCTestBase : public base::MultiProcessTest {
protected:
IPCTestBase();
- virtual ~IPCTestBase();
+ ~IPCTestBase() override;
- virtual void TearDown() override;
+ void TearDown() override;
// Initializes the test to use the given client and creates an IO message loop
// on the current thread.
@@ -100,11 +100,11 @@ class IPCTestBase : public base::MultiProcessTest {
IPC::Channel* channel() { return channel_.get(); }
IPC::ChannelProxy* channel_proxy() { return channel_proxy_.get(); }
- const base::ProcessHandle& client_process() const { return client_process_; }
- scoped_refptr<base::TaskRunner> task_runner();
+ const base::Process& client_process() const { return client_process_; }
+ scoped_refptr<base::SequencedTaskRunner> task_runner();
virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
- const IPC::ChannelHandle& handle, base::TaskRunner* runner);
+ const IPC::ChannelHandle& handle, base::SequencedTaskRunner* runner);
virtual bool DidStartClient();
@@ -117,7 +117,7 @@ class IPCTestBase : public base::MultiProcessTest {
scoped_ptr<IPC::Channel> channel_;
scoped_ptr<IPC::ChannelProxy> channel_proxy_;
- base::ProcessHandle client_process_;
+ base::Process client_process_;
DISALLOW_COPY_AND_ASSIGN(IPCTestBase);
};
diff --git a/chromium/ipc/ipc_test_sink.cc b/chromium/ipc/ipc_test_sink.cc
index 1f76c0484c3..53d29fc7845 100644
--- a/chromium/ipc/ipc_test_sink.cc
+++ b/chromium/ipc/ipc_test_sink.cc
@@ -41,7 +41,7 @@ base::ProcessId TestSink::GetSelfPID() const {
}
bool TestSink::OnMessageReceived(const Message& msg) {
- ObserverListBase<Listener>::Iterator it(filter_list_);
+ ObserverListBase<Listener>::Iterator it(&filter_list_);
Listener* observer;
while ((observer = it.GetNext()) != NULL) {
if (observer->OnMessageReceived(msg))
diff --git a/chromium/ipc/mojo/BUILD.gn b/chromium/ipc/mojo/BUILD.gn
index 324cc9ac9aa..50241fe4641 100644
--- a/chromium/ipc/mojo/BUILD.gn
+++ b/chromium/ipc/mojo/BUILD.gn
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//mojo/public/tools/bindings/mojom.gni")
+import("//testing/test.gni")
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
mojom("client_channel") {
sources = [
@@ -12,17 +13,25 @@ mojom("client_channel") {
component("mojo") {
sources = [
+ "async_handle_waiter.cc",
+ "async_handle_waiter.h",
"client_channel.mojom",
"ipc_channel_mojo.cc",
"ipc_channel_mojo.h",
"ipc_channel_mojo_host.cc",
"ipc_channel_mojo_host.h",
- "ipc_channel_mojo_readers.cc",
- "ipc_channel_mojo_readers.h",
- "ipc_mojo_bootstrap.cc",
- "ipc_mojo_bootstrap.h",
"ipc_message_pipe_reader.cc",
"ipc_message_pipe_reader.h",
+ "ipc_mojo_bootstrap.cc",
+ "ipc_mojo_bootstrap.h",
+ "ipc_mojo_handle_attachment.cc",
+ "ipc_mojo_handle_attachment.h",
+ "ipc_mojo_message_helper.cc",
+ "ipc_mojo_message_helper.h",
+ "ipc_mojo_param_traits.cc",
+ "ipc_mojo_param_traits.h",
+ "scoped_ipc_support.cc",
+ "scoped_ipc_support.h",
]
defines = [ "IPC_MOJO_IMPLEMENTATION" ]
@@ -32,14 +41,16 @@ component("mojo") {
"//base/third_party/dynamic_annotations",
"//ipc",
"//mojo/environment:chromium",
- "//mojo/public/cpp/bindings",
- "//mojo/edk/system",
+ "//third_party/mojo/src/mojo/edk/system",
+ "//third_party/mojo/src/mojo/public/c/environment:environment",
+ "//third_party/mojo/src/mojo/public/cpp/bindings",
":client_channel",
]
}
test("ipc_mojo_unittests") {
sources = [
+ "async_handle_waiter_unittest.cc",
"ipc_channel_mojo_unittest.cc",
"ipc_mojo_bootstrap_unittest.cc",
"run_all_unittests.cc",
@@ -52,8 +63,9 @@ test("ipc_mojo_unittests") {
"//ipc",
"//ipc:test_support",
"//ipc/mojo",
- "//mojo/edk/system",
"//mojo/environment:chromium",
+ "//testing/gtest",
+ "//third_party/mojo/src/mojo/edk/system",
"//url",
]
}
@@ -71,8 +83,8 @@ test("ipc_mojo_perftests") {
"//ipc",
"//ipc:test_support",
"//ipc/mojo",
- "//mojo/edk/system",
"//mojo/environment:chromium",
+ "//third_party/mojo/src/mojo/edk/system",
"//url",
]
}
diff --git a/chromium/ipc/mojo/DEPS b/chromium/ipc/mojo/DEPS
index 039e2432bf7..fb36693916b 100644
--- a/chromium/ipc/mojo/DEPS
+++ b/chromium/ipc/mojo/DEPS
@@ -1,4 +1,4 @@
include_rules = [
- "+mojo/public",
- "+mojo/edk/embedder",
+ "+third_party/mojo/src/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
new file mode 100644
index 00000000000..b9e68d7c453
--- /dev/null
+++ b/chromium/ipc/mojo/async_handle_waiter.cc
@@ -0,0 +1,165 @@
+// 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 "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 {
+ 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
new file mode 100644
index 00000000000..d6cc74510b2
--- /dev/null
+++ b/chromium/ipc/mojo/async_handle_waiter.h
@@ -0,0 +1,52 @@
+// 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/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "ipc/ipc_export.h"
+#include "third_party/mojo/src/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
new file mode 100644
index 00000000000..441b4ecd316
--- /dev/null
+++ b/chromium/ipc/mojo/async_handle_waiter_unittest.cc
@@ -0,0 +1,257 @@
+// 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/bind.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.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/ipc_channel_mojo.cc b/chromium/ipc/mojo/ipc_channel_mojo.cc
index 4051bb5c21a..e38a7e94ae8 100644
--- a/chromium/ipc/mojo/ipc_channel_mojo.cc
+++ b/chromium/ipc/mojo/ipc_channel_mojo.cc
@@ -7,15 +7,19 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/lazy_instance.h"
+#include "base/thread_task_runner_handle.h"
#include "ipc/ipc_listener.h"
+#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_channel_mojo_readers.h"
#include "ipc/mojo/ipc_mojo_bootstrap.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/public/cpp/bindings/error_handler.h"
+#include "ipc/mojo/ipc_mojo_handle_attachment.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
#if defined(OS_POSIX) && !defined(OS_NACL)
-#include "ipc/file_descriptor_set_posix.h"
+#include "ipc/ipc_platform_file_attachment_posix.h"
#endif
namespace IPC {
@@ -25,37 +29,44 @@ namespace {
class MojoChannelFactory : public ChannelFactory {
public:
MojoChannelFactory(ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
ChannelHandle channel_handle,
Channel::Mode mode)
- : delegate_(delegate), channel_handle_(channel_handle), mode_(mode) {}
+ : delegate_(delegate),
+ io_runner_(io_runner),
+ channel_handle_(channel_handle),
+ mode_(mode) {}
std::string GetName() const override {
return channel_handle_.name;
}
scoped_ptr<Channel> BuildChannel(Listener* listener) override {
- return ChannelMojo::Create(delegate_, channel_handle_, mode_, listener);
+ return ChannelMojo::Create(delegate_, io_runner_, channel_handle_, mode_,
+ listener);
}
private:
ChannelMojo::Delegate* delegate_;
+ scoped_refptr<base::TaskRunner> io_runner_;
ChannelHandle channel_handle_;
Channel::Mode mode_;
};
//------------------------------------------------------------------------------
-class ClientChannelMojo
- : public ChannelMojo,
- public NON_EXPORTED_BASE(mojo::InterfaceImpl<ClientChannel>) {
+class ClientChannelMojo : public ChannelMojo,
+ public ClientChannel,
+ public mojo::ErrorHandler {
public:
ClientChannelMojo(ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& handle,
Listener* listener);
~ClientChannelMojo() override;
// MojoBootstrap::Delegate implementation
void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) override;
- // InterfaceImpl implementation
+ // mojo::ErrorHandler implementation
void OnConnectionError() override;
// ClientChannel implementation
void Init(
@@ -63,13 +74,22 @@ class ClientChannelMojo
int32_t peer_pid,
const mojo::Callback<void(int32_t)>& callback) override;
+ private:
+ void BindPipe(mojo::ScopedMessagePipeHandle handle);
+
+ mojo::Binding<ClientChannel> binding_;
+ base::WeakPtrFactory<ClientChannelMojo> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ClientChannelMojo);
};
ClientChannelMojo::ClientChannelMojo(ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& handle,
Listener* listener)
- : ChannelMojo(delegate, handle, Channel::MODE_CLIENT, listener) {
+ : ChannelMojo(delegate, io_runner, handle, Channel::MODE_CLIENT, listener),
+ binding_(this),
+ weak_factory_(this) {
}
ClientChannelMojo::~ClientChannelMojo() {
@@ -77,7 +97,8 @@ ClientChannelMojo::~ClientChannelMojo() {
void ClientChannelMojo::OnPipeAvailable(
mojo::embedder::ScopedPlatformHandle handle) {
- mojo::WeakBindToPipe(this, CreateMessagingPipe(handle.Pass()));
+ CreateMessagingPipe(handle.Pass(), base::Bind(&ClientChannelMojo::BindPipe,
+ weak_factory_.GetWeakPtr()));
}
void ClientChannelMojo::OnConnectionError() {
@@ -92,36 +113,47 @@ void ClientChannelMojo::Init(
callback.Run(GetSelfPID());
}
+void ClientChannelMojo::BindPipe(mojo::ScopedMessagePipeHandle handle) {
+ binding_.Bind(handle.Pass());
+}
+
//------------------------------------------------------------------------------
class ServerChannelMojo : public ChannelMojo, public mojo::ErrorHandler {
public:
ServerChannelMojo(ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& handle,
Listener* listener);
~ServerChannelMojo() override;
// MojoBootstrap::Delegate implementation
void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) override;
- // ErrorHandler implementation
+ // mojo::ErrorHandler implementation
void OnConnectionError() override;
// Channel override
void Close() override;
private:
+ void InitClientChannel(mojo::ScopedMessagePipeHandle peer_handle,
+ mojo::ScopedMessagePipeHandle handle);
+
// ClientChannelClient implementation
void ClientChannelWasInitialized(int32_t peer_pid);
mojo::InterfacePtr<ClientChannel> client_channel_;
mojo::ScopedMessagePipeHandle message_pipe_;
+ base::WeakPtrFactory<ServerChannelMojo> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServerChannelMojo);
};
ServerChannelMojo::ServerChannelMojo(ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& handle,
Listener* listener)
- : ChannelMojo(delegate, handle, Channel::MODE_SERVER, listener) {
+ : ChannelMojo(delegate, io_runner, handle, Channel::MODE_SERVER, listener),
+ weak_factory_(this) {
}
ServerChannelMojo::~ServerChannelMojo() {
@@ -134,16 +166,24 @@ void ServerChannelMojo::OnPipeAvailable(
MojoResult create_result =
mojo::CreateMessagePipe(nullptr, &message_pipe_, &peer);
if (create_result != MOJO_RESULT_OK) {
- DLOG(WARNING) << "mojo::CreateMessagePipe failed: " << create_result;
+ LOG(WARNING) << "mojo::CreateMessagePipe failed: " << create_result;
listener()->OnChannelError();
return;
}
+ CreateMessagingPipe(
+ handle.Pass(),
+ base::Bind(&ServerChannelMojo::InitClientChannel,
+ weak_factory_.GetWeakPtr(), base::Passed(&peer)));
+}
- client_channel_.Bind(CreateMessagingPipe(handle.Pass()));
+void ServerChannelMojo::InitClientChannel(
+ mojo::ScopedMessagePipeHandle peer_handle,
+ mojo::ScopedMessagePipeHandle handle) {
+ client_channel_.Bind(
+ mojo::InterfacePtrInfo<ClientChannel>(handle.Pass(), 0u));
client_channel_.set_error_handler(this);
client_channel_->Init(
- peer.Pass(),
- static_cast<int32_t>(GetSelfPID()),
+ peer_handle.Pass(), static_cast<int32_t>(GetSelfPID()),
base::Bind(&ServerChannelMojo::ClientChannelWasInitialized,
base::Unretained(this)));
}
@@ -162,35 +202,59 @@ void ServerChannelMojo::Close() {
ChannelMojo::Close();
}
-} // namespace
+#if defined(OS_POSIX) && !defined(OS_NACL)
+
+base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) {
+ return attachment->Owns() ? base::ScopedFD(attachment->TakePlatformFile())
+ : base::ScopedFD(dup(attachment->file()));
+}
+
+#endif
+
+} // namespace
//------------------------------------------------------------------------------
+ChannelMojo::ChannelInfoDeleter::ChannelInfoDeleter(
+ scoped_refptr<base::TaskRunner> io_runner)
+ : io_runner(io_runner) {
+}
+
+ChannelMojo::ChannelInfoDeleter::~ChannelInfoDeleter() {
+}
+
void ChannelMojo::ChannelInfoDeleter::operator()(
mojo::embedder::ChannelInfo* ptr) const {
- mojo::embedder::DestroyChannelOnIOThread(ptr);
+ if (base::ThreadTaskRunnerHandle::Get() == io_runner) {
+ mojo::embedder::DestroyChannelOnIOThread(ptr);
+ } else {
+ io_runner->PostTask(
+ FROM_HERE, base::Bind(&mojo::embedder::DestroyChannelOnIOThread, ptr));
+ }
}
//------------------------------------------------------------------------------
// static
bool ChannelMojo::ShouldBeUsed() {
- // TODO(morrita): Turn this on for a set of platforms.
- return false;
+ // TODO(morrita): Remove this if it sticks.
+ return true;
}
// static
-scoped_ptr<ChannelMojo> ChannelMojo::Create(ChannelMojo::Delegate* delegate,
- const ChannelHandle& channel_handle,
- Mode mode,
- Listener* listener) {
+scoped_ptr<ChannelMojo> ChannelMojo::Create(
+ ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
+ const ChannelHandle& channel_handle,
+ Mode mode,
+ Listener* listener) {
switch (mode) {
case Channel::MODE_CLIENT:
return make_scoped_ptr(
- new ClientChannelMojo(delegate, channel_handle, listener));
+ new ClientChannelMojo(delegate, io_runner, channel_handle, listener));
case Channel::MODE_SERVER:
return make_scoped_ptr(
- new ServerChannelMojo(delegate, channel_handle, listener));
+ new ServerChannelMojo(delegate, io_runner, channel_handle, listener));
default:
NOTREACHED();
return nullptr;
@@ -200,39 +264,41 @@ scoped_ptr<ChannelMojo> ChannelMojo::Create(ChannelMojo::Delegate* delegate,
// static
scoped_ptr<ChannelFactory> ChannelMojo::CreateServerFactory(
ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& channel_handle) {
- return make_scoped_ptr(
- new MojoChannelFactory(delegate, channel_handle, Channel::MODE_SERVER));
+ return make_scoped_ptr(new MojoChannelFactory(
+ delegate, io_runner, channel_handle, Channel::MODE_SERVER));
}
// static
scoped_ptr<ChannelFactory> ChannelMojo::CreateClientFactory(
+ ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& channel_handle) {
- return make_scoped_ptr(
- new MojoChannelFactory(NULL, channel_handle, Channel::MODE_CLIENT));
+ return make_scoped_ptr(new MojoChannelFactory(
+ delegate, io_runner, channel_handle, Channel::MODE_CLIENT));
}
ChannelMojo::ChannelMojo(ChannelMojo::Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& handle,
Mode mode,
Listener* listener)
: mode_(mode),
listener_(listener),
peer_pid_(base::kNullProcessId),
+ io_runner_(io_runner),
+ channel_info_(nullptr, ChannelInfoDeleter(nullptr)),
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 (delegate) {
- if (delegate->GetIOTaskRunner() ==
- base::MessageLoop::current()->message_loop_proxy()) {
- InitDelegate(delegate);
- } else {
- delegate->GetIOTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(
- &ChannelMojo::InitDelegate, base::Unretained(this), delegate));
- }
+ if (io_runner == base::MessageLoop::current()->task_runner()) {
+ InitOnIOThread(delegate);
+ } else {
+ io_runner->PostTask(FROM_HERE,
+ base::Bind(&ChannelMojo::InitOnIOThread,
+ base::Unretained(this), delegate));
}
}
@@ -240,19 +306,56 @@ ChannelMojo::~ChannelMojo() {
Close();
}
-void ChannelMojo::InitDelegate(ChannelMojo::Delegate* delegate) {
+void ChannelMojo::InitOnIOThread(ChannelMojo::Delegate* delegate) {
+ ipc_support_.reset(
+ new ScopedIPCSupport(base::MessageLoop::current()->task_runner()));
+ if (!delegate)
+ return;
delegate_ = delegate->ToWeakPtr();
delegate_->OnChannelCreated(weak_factory_.GetWeakPtr());
}
-mojo::ScopedMessagePipeHandle ChannelMojo::CreateMessagingPipe(
- mojo::embedder::ScopedPlatformHandle handle) {
- DCHECK(!channel_info_.get());
+void ChannelMojo::CreateMessagingPipe(
+ mojo::embedder::ScopedPlatformHandle handle,
+ const CreateMessagingPipeCallback& callback) {
+ auto return_callback = base::Bind(&ChannelMojo::OnMessagingPipeCreated,
+ weak_factory_.GetWeakPtr(), callback);
+ if (base::ThreadTaskRunnerHandle::Get() == io_runner_) {
+ CreateMessagingPipeOnIOThread(
+ handle.Pass(), 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(handle.Pass(), &channel_info);
- channel_info_.reset(channel_info);
- return pipe.Pass();
+ if (base::ThreadTaskRunnerHandle::Get() == callback_runner) {
+ callback.Run(pipe.Pass(), 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(handle.Pass());
}
bool ChannelMojo::Connect() {
@@ -261,33 +364,68 @@ bool ChannelMojo::Connect() {
}
void ChannelMojo::Close() {
- message_reader_.reset();
+ scoped_ptr<internal::MessagePipeReader, ReaderDeleter> to_be_deleted;
+
+ {
+ // |message_reader_| has to be cleared inside the lock,
+ // but the instance has to be deleted outside.
+ base::AutoLock l(lock_);
+ to_be_deleted = message_reader_.Pass();
+ }
+
channel_info_.reset();
+ ipc_support_.reset();
+ to_be_deleted.reset();
}
void ChannelMojo::OnBootstrapError() {
listener_->OnChannelError();
}
+namespace {
+
+// ClosingDeleter calls |CloseWithErrorIfPending| before deleting the
+// |MessagePipeReader|.
+struct ClosingDeleter {
+ typedef base::DefaultDeleter<internal::MessagePipeReader> DefaultType;
+
+ void operator()(internal::MessagePipeReader* ptr) const {
+ ptr->CloseWithErrorIfPending();
+ delete ptr;
+ }
+};
+
+} // namespace
+
void ChannelMojo::InitMessageReader(mojo::ScopedMessagePipeHandle pipe,
int32_t peer_pid) {
- message_reader_ =
- make_scoped_ptr(new internal::MessageReader(pipe.Pass(), this));
-
- for (size_t i = 0; i < pending_messages_.size(); ++i) {
- bool sent = message_reader_->Send(make_scoped_ptr(pending_messages_[i]));
- pending_messages_[i] = NULL;
- if (!sent) {
- pending_messages_.clear();
- listener_->OnChannelError();
- return;
+ scoped_ptr<internal::MessagePipeReader, ClosingDeleter> reader(
+ new internal::MessagePipeReader(pipe.Pass(), this));
+
+ {
+ base::AutoLock l(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.
+ pending_messages_.clear();
+ LOG(ERROR) << "Failed to flush pending messages";
+ return;
+ }
}
- }
- pending_messages_.clear();
+ // 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();
+ }
set_peer_pid(peer_pid);
listener_->OnChannelConnected(static_cast<int32_t>(GetPeerPID()));
+ if (message_reader_)
+ message_reader_->ReadMessagesThenWait();
}
void ChannelMojo::OnPipeClosed(internal::MessagePipeReader* reader) {
@@ -299,7 +437,9 @@ void ChannelMojo::OnPipeError(internal::MessagePipeReader* reader) {
}
+// Warning: Keep the implementation thread-safe.
bool ChannelMojo::Send(Message* message) {
+ base::AutoLock l(lock_);
if (!message_reader_) {
pending_messages_.push_back(message);
return true;
@@ -308,12 +448,16 @@ bool ChannelMojo::Send(Message* message) {
return message_reader_->Send(make_scoped_ptr(message));
}
+bool ChannelMojo::IsSendThreadSafe() const {
+ return false;
+}
+
base::ProcessId ChannelMojo::GetPeerPID() const {
return peer_pid_;
}
base::ProcessId ChannelMojo::GetSelfPID() const {
- return base::GetCurrentProcId();
+ return bootstrap_->GetSelfPID();
}
void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) {
@@ -321,6 +465,9 @@ void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) {
}
void ChannelMojo::OnMessageReceived(Message& message) {
+ TRACE_EVENT2("ipc,toplevel", "ChannelMojo::OnMessageReceived",
+ "class", IPC_MESSAGE_ID_CLASS(message.type()),
+ "line", IPC_MESSAGE_ID_LINE(message.type()));
listener_->OnMessageReceived(message);
if (message.dispatch_error())
listener_->OnBadMessageReceived(message);
@@ -334,69 +481,81 @@ int ChannelMojo::GetClientFileDescriptor() const {
base::ScopedFD ChannelMojo::TakeClientFileDescriptor() {
return bootstrap_->TakeClientFileDescriptor();
}
+#endif // defined(OS_POSIX) && !defined(OS_NACL)
// static
-MojoResult ChannelMojo::WriteToFileDescriptorSet(
- const std::vector<MojoHandle>& handle_buffer,
- Message* message) {
- for (size_t i = 0; i < handle_buffer.size(); ++i) {
- mojo::embedder::ScopedPlatformHandle platform_handle;
- MojoResult unwrap_result = mojo::embedder::PassWrappedPlatformHandle(
- handle_buffer[i], &platform_handle);
- if (unwrap_result != MOJO_RESULT_OK) {
- DLOG(WARNING) << "Pipe failed to covert handles. Closing: "
- << unwrap_result;
- return unwrap_result;
+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.
+ if (message->HasAttachments()) {
+ MessageAttachmentSet* set = message->attachment_set();
+ for (unsigned i = 0; i < set->size(); ++i) {
+ scoped_refptr<MessageAttachment> attachment = set->GetAttachmentAt(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->CommitAll();
+ return MOJO_RESULT_UNKNOWN;
+ }
+
+ MojoHandle wrapped_handle;
+ MojoResult wrap_result = 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->CommitAll();
+ 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;
+ }
}
- bool ok = message->file_descriptor_set()->AddToOwn(
- base::ScopedFD(platform_handle.release().fd));
- DCHECK(ok);
+ set->CommitAll();
}
return MOJO_RESULT_OK;
}
// static
-MojoResult ChannelMojo::ReadFromFileDescriptorSet(
- Message* message,
- std::vector<MojoHandle>* handles) {
- // We dup() the handles in IPC::Message to transmit.
- // IPC::FileDescriptorSet has intricate lifecycle semantics
- // of FDs, so just to dup()-and-own them is the safest option.
- if (message->HasFileDescriptors()) {
- FileDescriptorSet* fdset = message->file_descriptor_set();
- std::vector<base::PlatformFile> fds_to_send(fdset->size());
- fdset->PeekDescriptors(&fds_to_send[0]);
- for (size_t i = 0; i < fds_to_send.size(); ++i) {
- int fd_to_send = dup(fds_to_send[i]);
- if (-1 == fd_to_send) {
- DPLOG(WARNING) << "Failed to dup FD to transmit.";
- fdset->CommitAll();
- return MOJO_RESULT_UNKNOWN;
- }
-
- MojoHandle wrapped_handle;
- MojoResult wrap_result = CreatePlatformHandleWrapper(
- mojo::embedder::ScopedPlatformHandle(
- mojo::embedder::PlatformHandle(fd_to_send)),
- &wrapped_handle);
- if (MOJO_RESULT_OK != wrap_result) {
- DLOG(WARNING) << "Pipe failed to wrap handles. Closing: "
- << wrap_result;
- fdset->CommitAll();
- return wrap_result;
- }
-
- handles->push_back(wrapped_handle);
+MojoResult ChannelMojo::WriteToMessageAttachmentSet(
+ const std::vector<MojoHandle>& handle_buffer,
+ Message* message) {
+ for (size_t i = 0; i < handle_buffer.size(); ++i) {
+ bool ok = message->attachment_set()->AddAttachment(
+ new IPC::internal::MojoHandleAttachment(
+ mojo::MakeScopedHandle(mojo::Handle(handle_buffer[i]))));
+ DCHECK(ok);
+ if (!ok) {
+ LOG(ERROR) << "Failed to add new Mojo handle.";
+ return MOJO_RESULT_UNKNOWN;
}
-
- fdset->CommitAll();
}
return MOJO_RESULT_OK;
}
-#endif // defined(OS_POSIX) && !defined(OS_NACL)
-
} // namespace IPC
diff --git a/chromium/ipc/mojo/ipc_channel_mojo.h b/chromium/ipc/mojo/ipc_channel_mojo.h
index 29d5f29b3e7..3a1d98a8a97 100644
--- a/chromium/ipc/mojo/ipc_channel_mojo.h
+++ b/chromium/ipc/mojo/ipc_channel_mojo.h
@@ -10,23 +10,18 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.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 "mojo/edk/embedder/channel_info_forward.h"
-#include "mojo/public/cpp/system/core.h"
+#include "ipc/mojo/scoped_ipc_support.h"
+#include "third_party/mojo/src/mojo/edk/embedder/channel_info_forward.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/core.h"
namespace IPC {
-namespace internal {
-class ControlReader;
-class ServerControlReader;
-class ClientControlReader;
-class MessageReader;
-}
-
// Mojo-based IPC::Channel implementation over a platform handle.
//
// ChannelMojo builds Mojo MessagePipe using underlying pipe given by
@@ -51,14 +46,21 @@ class MessageReader;
// TODO(morrita): Add APIs to create extra MessagePipes to let
// Mojo-based objects talk over this Channel.
//
-class IPC_MOJO_EXPORT ChannelMojo : public Channel,
- public MojoBootstrap::Delegate {
+class IPC_MOJO_EXPORT ChannelMojo
+ : public Channel,
+ 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*)>;
+
class Delegate {
public:
virtual ~Delegate() {}
virtual base::WeakPtr<Delegate> ToWeakPtr() = 0;
- virtual scoped_refptr<base::TaskRunner> GetIOTaskRunner() = 0;
virtual void OnChannelCreated(base::WeakPtr<ChannelMojo> channel) = 0;
};
@@ -67,19 +69,24 @@ class IPC_MOJO_EXPORT ChannelMojo : public Channel,
// Create ChannelMojo. A bootstrap channel is created as well.
// |host| must not be null for server channels.
- static scoped_ptr<ChannelMojo> Create(Delegate* delegate,
- const ChannelHandle& channel_handle,
- Mode mode,
- Listener* listener);
+ static scoped_ptr<ChannelMojo> Create(
+ Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
+ const ChannelHandle& channel_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(
Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& channel_handle);
static scoped_ptr<ChannelFactory> CreateClientFactory(
+ Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& channel_handle);
~ChannelMojo() override;
@@ -91,39 +98,41 @@ class IPC_MOJO_EXPORT ChannelMojo : public Channel,
bool Connect() override;
void Close() override;
bool Send(Message* message) override;
+ bool IsSendThreadSafe() const override;
base::ProcessId GetPeerPID() const override;
base::ProcessId GetSelfPID() const override;
#if defined(OS_POSIX) && !defined(OS_NACL)
int GetClientFileDescriptor() const override;
base::ScopedFD TakeClientFileDescriptor() override;
+#endif // defined(OS_POSIX) && !defined(OS_NACL)
// These access protected API of IPC::Message, which has ChannelMojo
// as a friend class.
- static MojoResult WriteToFileDescriptorSet(
+ static MojoResult WriteToMessageAttachmentSet(
const std::vector<MojoHandle>& handle_buffer,
Message* message);
- static MojoResult ReadFromFileDescriptorSet(Message* message,
- std::vector<MojoHandle>* handles);
-
-#endif // defined(OS_POSIX) && !defined(OS_NACL)
+ static MojoResult ReadFromMessageAttachmentSet(
+ Message* message,
+ std::vector<MojoHandle>* handles);
// MojoBootstrapDelegate implementation
void OnBootstrapError() override;
- // Called from MessagePipeReader implementations
- void OnMessageReceived(Message& message);
- void OnPipeClosed(internal::MessagePipeReader* reader);
- void OnPipeError(internal::MessagePipeReader* reader);
+ // MessagePipeReader::Delegate
+ void OnMessageReceived(Message& message) override;
+ void OnPipeClosed(internal::MessagePipeReader* reader) override;
+ void OnPipeError(internal::MessagePipeReader* reader) override;
protected:
ChannelMojo(Delegate* delegate,
+ scoped_refptr<base::TaskRunner> io_runner,
const ChannelHandle& channel_handle,
Mode mode,
Listener* listener);
- mojo::ScopedMessagePipeHandle CreateMessagingPipe(
- mojo::embedder::ScopedPlatformHandle handle);
+ void CreateMessagingPipe(mojo::embedder::ScopedPlatformHandle handle,
+ const CreateMessagingPipeCallback& callback);
void InitMessageReader(mojo::ScopedMessagePipeHandle pipe, int32_t peer_pid);
Listener* listener() const { return listener_; }
@@ -131,7 +140,12 @@ class IPC_MOJO_EXPORT ChannelMojo : public Channel,
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;
};
// ChannelMojo needs to kill its MessagePipeReader in delayed manner
@@ -139,19 +153,36 @@ class IPC_MOJO_EXPORT ChannelMojo : public Channel,
// notifications invoked by them.
typedef internal::MessagePipeReader::DelayedDeleter ReaderDeleter;
- void InitDelegate(ChannelMojo::Delegate* delegate);
+ void InitOnIOThread(ChannelMojo::Delegate* delegate);
+
+ 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);
scoped_ptr<MojoBootstrap> bootstrap_;
base::WeakPtr<Delegate> delegate_;
Mode mode_;
Listener* listener_;
base::ProcessId peer_pid_;
+ scoped_refptr<base::TaskRunner> io_runner_;
scoped_ptr<mojo::embedder::ChannelInfo,
ChannelInfoDeleter> channel_info_;
- scoped_ptr<internal::MessageReader, ReaderDeleter> message_reader_;
+ // Guards |message_reader_| 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_;
+ scoped_ptr<internal::MessagePipeReader, ReaderDeleter> message_reader_;
ScopedVector<Message> pending_messages_;
+ scoped_ptr<ScopedIPCSupport> ipc_support_;
+
base::WeakPtrFactory<ChannelMojo> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ChannelMojo);
diff --git a/chromium/ipc/mojo/ipc_channel_mojo_host.cc b/chromium/ipc/mojo/ipc_channel_mojo_host.cc
index beb18ee5e99..ac914ad2aff 100644
--- a/chromium/ipc/mojo/ipc_channel_mojo_host.cc
+++ b/chromium/ipc/mojo/ipc_channel_mojo_host.cc
@@ -5,32 +5,44 @@
#include "ipc/mojo/ipc_channel_mojo_host.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "ipc/mojo/ipc_channel_mojo.h"
namespace IPC {
+class ChannelMojoHost::ChannelDelegateTraits {
+ public:
+ static void Destruct(const ChannelMojoHost::ChannelDelegate* ptr);
+};
+
// The delete class lives on the IO thread to talk to ChannelMojo on
// behalf of ChannelMojoHost.
//
// The object must be touched only on the IO thread.
-class ChannelMojoHost::ChannelDelegate : public ChannelMojo::Delegate {
+class ChannelMojoHost::ChannelDelegate
+ : public base::RefCountedThreadSafe<ChannelMojoHost::ChannelDelegate,
+ ChannelMojoHost::ChannelDelegateTraits>,
+ public ChannelMojo::Delegate {
public:
- explicit ChannelDelegate(scoped_refptr<base::TaskRunner> io_task_runner);
- ~ChannelDelegate() override;
+ explicit ChannelDelegate(
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner);
// ChannelMojo::Delegate
base::WeakPtr<Delegate> ToWeakPtr() override;
void OnChannelCreated(base::WeakPtr<ChannelMojo> channel) override;
- scoped_refptr<base::TaskRunner> GetIOTaskRunner() override;
// Returns an weak ptr of ChannelDelegate instead of Delegate
base::WeakPtr<ChannelDelegate> GetWeakPtr();
void OnClientLaunched(base::ProcessHandle process);
- void DeleteThisSoon();
+ void DeleteThisSoon() const;
private:
- scoped_refptr<base::TaskRunner> io_task_runner_;
+ friend class base::DeleteHelper<ChannelDelegate>;
+
+ ~ChannelDelegate() override;
+
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
base::WeakPtr<ChannelMojo> channel_;
base::WeakPtrFactory<ChannelDelegate> weak_factory_;
@@ -38,7 +50,7 @@ class ChannelMojoHost::ChannelDelegate : public ChannelMojo::Delegate {
};
ChannelMojoHost::ChannelDelegate::ChannelDelegate(
- scoped_refptr<base::TaskRunner> io_task_runner)
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner)
: io_task_runner_(io_task_runner), weak_factory_(this) {
}
@@ -61,29 +73,22 @@ void ChannelMojoHost::ChannelDelegate::OnChannelCreated(
channel_ = channel;
}
-scoped_refptr<base::TaskRunner>
-ChannelMojoHost::ChannelDelegate::GetIOTaskRunner() {
- return io_task_runner_;
-}
-
void ChannelMojoHost::ChannelDelegate::OnClientLaunched(
base::ProcessHandle process) {
if (channel_)
channel_->OnClientLaunched(process);
}
-void ChannelMojoHost::ChannelDelegate::DeleteThisSoon() {
- io_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&base::DeletePointer<ChannelMojoHost::ChannelDelegate>,
- base::Unretained(this)));
+void ChannelMojoHost::ChannelDelegate::DeleteThisSoon() const {
+ io_task_runner_->DeleteSoon(FROM_HERE, this);
}
//
// ChannelMojoHost
//
-ChannelMojoHost::ChannelMojoHost(scoped_refptr<base::TaskRunner> io_task_runner)
+ChannelMojoHost::ChannelMojoHost(
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner)
: io_task_runner_(io_task_runner),
channel_delegate_(new ChannelDelegate(io_task_runner)),
weak_factory_(this) {
@@ -93,13 +98,12 @@ ChannelMojoHost::~ChannelMojoHost() {
}
void ChannelMojoHost::OnClientLaunched(base::ProcessHandle process) {
- if (io_task_runner_ == base::MessageLoop::current()->message_loop_proxy()) {
+ if (io_task_runner_ == base::MessageLoop::current()->task_runner()) {
channel_delegate_->OnClientLaunched(process);
} else {
io_task_runner_->PostTask(FROM_HERE,
base::Bind(&ChannelDelegate::OnClientLaunched,
- channel_delegate_->GetWeakPtr(),
- process));
+ channel_delegate_, process));
}
}
@@ -107,8 +111,9 @@ ChannelMojo::Delegate* ChannelMojoHost::channel_delegate() const {
return channel_delegate_.get();
}
-void ChannelMojoHost::DelegateDeleter::operator()(
- ChannelMojoHost::ChannelDelegate* ptr) const {
+// static
+void ChannelMojoHost::ChannelDelegateTraits::Destruct(
+ const ChannelMojoHost::ChannelDelegate* ptr) {
ptr->DeleteThisSoon();
}
diff --git a/chromium/ipc/mojo/ipc_channel_mojo_host.h b/chromium/ipc/mojo/ipc_channel_mojo_host.h
index 8289515fc31..db60b12a4cc 100644
--- a/chromium/ipc/mojo/ipc_channel_mojo_host.h
+++ b/chromium/ipc/mojo/ipc_channel_mojo_host.h
@@ -12,7 +12,7 @@
#include "ipc/mojo/ipc_channel_mojo.h"
namespace base {
-class TaskRunner;
+class SequencedTaskRunner;
}
namespace IPC {
@@ -23,7 +23,8 @@ namespace IPC {
// instance and call OnClientLaunched().
class IPC_MOJO_EXPORT ChannelMojoHost {
public:
- explicit ChannelMojoHost(scoped_refptr<base::TaskRunner> io_task_runner);
+ explicit ChannelMojoHost(
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner);
~ChannelMojoHost();
void OnClientLaunched(base::ProcessHandle process);
@@ -31,16 +32,10 @@ class IPC_MOJO_EXPORT ChannelMojoHost {
private:
class ChannelDelegate;
+ class ChannelDelegateTraits;
- // Delegate talks to ChannelMojo, whch lives in IO thread, thus
- // the Delegate should also live and dies in the IO thread as well.
- class DelegateDeleter {
- public:
- void operator()(ChannelDelegate* ptr) const;
- };
-
- const scoped_refptr<base::TaskRunner> io_task_runner_;
- scoped_ptr<ChannelDelegate, DelegateDeleter> channel_delegate_;
+ const scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
+ scoped_refptr<ChannelDelegate> channel_delegate_;
base::WeakPtrFactory<ChannelMojoHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ChannelMojoHost);
diff --git a/chromium/ipc/mojo/ipc_channel_mojo_readers.cc b/chromium/ipc/mojo/ipc_channel_mojo_readers.cc
deleted file mode 100644
index e4a35c584e5..00000000000
--- a/chromium/ipc/mojo/ipc_channel_mojo_readers.cc
+++ /dev/null
@@ -1,84 +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.
-
-#include "ipc/mojo/ipc_channel_mojo_readers.h"
-
-#include "ipc/mojo/ipc_channel_mojo.h"
-
-namespace IPC {
-namespace internal {
-
-//------------------------------------------------------------------------------
-
-MessageReader::MessageReader(mojo::ScopedMessagePipeHandle pipe,
- ChannelMojo* owner)
- : internal::MessagePipeReader(pipe.Pass()), owner_(owner) {
-}
-
-void MessageReader::OnMessageReceived() {
- Message message(data_buffer().empty() ? "" : &data_buffer()[0],
- static_cast<uint32>(data_buffer().size()));
-
- std::vector<MojoHandle> handle_buffer;
- TakeHandleBuffer(&handle_buffer);
-#if defined(OS_POSIX) && !defined(OS_NACL)
- MojoResult write_result =
- ChannelMojo::WriteToFileDescriptorSet(handle_buffer, &message);
- if (write_result != MOJO_RESULT_OK) {
- CloseWithError(write_result);
- return;
- }
-#else
- DCHECK(handle_buffer.empty());
-#endif
-
- message.TraceMessageEnd();
- owner_->OnMessageReceived(message);
-}
-
-void MessageReader::OnPipeClosed() {
- if (!owner_)
- return;
- owner_->OnPipeClosed(this);
- owner_ = NULL;
-}
-
-void MessageReader::OnPipeError(MojoResult error) {
- if (!owner_)
- return;
- owner_->OnPipeError(this);
-}
-
-bool MessageReader::Send(scoped_ptr<Message> message) {
- DCHECK(IsValid());
-
- message->TraceMessageBegin();
- std::vector<MojoHandle> handles;
-#if defined(OS_POSIX) && !defined(OS_NACL)
- MojoResult read_result =
- ChannelMojo::ReadFromFileDescriptorSet(message.get(), &handles);
- if (read_result != MOJO_RESULT_OK) {
- std::for_each(handles.begin(), handles.end(), &MojoClose);
- CloseWithError(read_result);
- return false;
- }
-#endif
- MojoResult write_result =
- MojoWriteMessage(handle(),
- message->data(),
- static_cast<uint32>(message->size()),
- handles.empty() ? NULL : &handles[0],
- static_cast<uint32>(handles.size()),
- MOJO_WRITE_MESSAGE_FLAG_NONE);
- if (MOJO_RESULT_OK != write_result) {
- std::for_each(handles.begin(), handles.end(), &MojoClose);
- CloseWithError(write_result);
- return false;
- }
-
- return true;
-}
-
-} // namespace internal
-} // namespace IPC
diff --git a/chromium/ipc/mojo/ipc_channel_mojo_readers.h b/chromium/ipc/mojo/ipc_channel_mojo_readers.h
deleted file mode 100644
index ffcc08bac5f..00000000000
--- a/chromium/ipc/mojo/ipc_channel_mojo_readers.h
+++ /dev/null
@@ -1,96 +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.
-
-#ifndef IPC_MOJO_IPC_CHANNEL_MOJO_READERS_H_
-#define IPC_MOJO_IPC_CHANNEL_MOJO_READERS_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "ipc/mojo/ipc_message_pipe_reader.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace IPC {
-
-class ChannelMojo;
-class Message;
-
-namespace internal {
-
-// A MessagePipeReader implementation for IPC::Message communication.
-class MessageReader : public MessagePipeReader {
- public:
- MessageReader(mojo::ScopedMessagePipeHandle pipe, ChannelMojo* owner);
-
- bool Send(scoped_ptr<Message> message);
-
- // MessagePipeReader implementation
- void OnMessageReceived() override;
- void OnPipeClosed() override;
- void OnPipeError(MojoResult error) override;
-
- private:
- ChannelMojo* owner_;
-
- DISALLOW_COPY_AND_ASSIGN(MessageReader);
-};
-
-// MessagePipeReader implementation for control messages.
-// Actual message handling is implemented by sublcasses.
-class ControlReader : public MessagePipeReader {
- public:
- ControlReader(mojo::ScopedMessagePipeHandle pipe, ChannelMojo* owner);
-
- virtual bool Connect();
-
- // MessagePipeReader implementation
- void OnPipeClosed() override;
- void OnPipeError(MojoResult error) override;
-
- protected:
- ChannelMojo* owner_;
-
- DISALLOW_COPY_AND_ASSIGN(ControlReader);
-};
-
-// ControlReader for server-side ChannelMojo.
-class ServerControlReader : public ControlReader {
- public:
- ServerControlReader(mojo::ScopedMessagePipeHandle pipe, ChannelMojo* owner);
- ~ServerControlReader() override;
-
- // ControlReader override
- bool Connect() override;
-
- // MessagePipeReader implementation
- void OnMessageReceived() override;
-
- private:
- MojoResult SendHelloRequest();
- MojoResult RespondHelloResponse();
-
- mojo::ScopedMessagePipeHandle message_pipe_;
-
- DISALLOW_COPY_AND_ASSIGN(ServerControlReader);
-};
-
-// ControlReader for client-side ChannelMojo.
-class ClientControlReader : public ControlReader {
- public:
- ClientControlReader(mojo::ScopedMessagePipeHandle pipe, ChannelMojo* owner);
-
- // MessagePipeReader implementation
- void OnMessageReceived() override;
-
- private:
- MojoResult RespondHelloRequest(MojoHandle message_channel);
-
- DISALLOW_COPY_AND_ASSIGN(ClientControlReader);
-};
-
-} // namespace internal
-} // namespace IPC
-
-#endif // IPC_MOJO_IPC_CHANNEL_MOJO_READERS_H_
diff --git a/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc b/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc
index 07218c69297..53c6ecfd04d 100644
--- a/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc
+++ b/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc
@@ -6,18 +6,26 @@
#include "base/base_paths.h"
#include "base/files/file.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
#include "base/path_service.h"
#include "base/pickle.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_test_base.h"
#include "ipc/ipc_test_channel_listener.h"
#include "ipc/mojo/ipc_channel_mojo_host.h"
-#include "ipc/mojo/ipc_channel_mojo_readers.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"
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
+#include "ipc/ipc_platform_file_attachment_posix.h"
#endif
namespace {
@@ -60,16 +68,24 @@ class ListenerThatExpectsOK : public IPC::Listener {
class ChannelClient {
public:
explicit ChannelClient(IPC::Listener* listener, const char* name) {
- channel_ = IPC::ChannelMojo::Create(NULL,
+ channel_ = IPC::ChannelMojo::Create(NULL, main_message_loop_.task_runner(),
IPCTestBase::GetChannelName(name),
- IPC::Channel::MODE_CLIENT,
- listener);
+ IPC::Channel::MODE_CLIENT, listener);
}
void Connect() {
CHECK(channel_->Connect());
}
+ void Close() {
+ channel_->Close();
+
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
IPC::ChannelMojo* channel() const { return channel_.get(); }
private:
@@ -77,20 +93,37 @@ class ChannelClient {
scoped_ptr<IPC::ChannelMojo> channel_;
};
-class IPCChannelMojoTest : public IPCTestBase {
+class IPCChannelMojoTestBase : public IPCTestBase {
+ public:
+ void InitWithMojo(const std::string& test_client_name) {
+ Init(test_client_name);
+ }
+
+ 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();
+
+ IPCTestBase::TearDown();
+ }
+};
+
+class IPCChannelMojoTest : public IPCChannelMojoTestBase {
protected:
scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
const IPC::ChannelHandle& handle,
- base::TaskRunner* runner) override {
+ base::SequencedTaskRunner* runner) override {
host_.reset(new IPC::ChannelMojoHost(task_runner()));
return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
- handle);
+ task_runner(), handle);
}
bool DidStartClient() override {
bool ok = IPCTestBase::DidStartClient();
DCHECK(ok);
- host_->OnClientLaunched(client_process());
+ host_->OnClientLaunched(client_process().Handle());
return ok;
}
@@ -119,7 +152,7 @@ class TestChannelListenerWithExtraExpectations
};
TEST_F(IPCChannelMojoTest, ConnectedFromClient) {
- Init("IPCChannelMojoTestClient");
+ InitWithMojo("IPCChannelMojoTestClient");
// Set up IPC channel and start client.
TestChannelListenerWithExtraExpectations listener;
@@ -156,6 +189,8 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) {
EXPECT_TRUE(listener.is_connected_called());
EXPECT_TRUE(listener.HasSentAll());
+ client.Close();
+
return 0;
}
@@ -183,20 +218,20 @@ class ListenerExpectingErrors : public IPC::Listener {
};
-class IPCChannelMojoErrorTest : public IPCTestBase {
+class IPCChannelMojoErrorTest : public IPCChannelMojoTestBase {
protected:
scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
const IPC::ChannelHandle& handle,
- base::TaskRunner* runner) override {
+ base::SequencedTaskRunner* runner) override {
host_.reset(new IPC::ChannelMojoHost(task_runner()));
return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
- handle);
+ task_runner(), handle);
}
bool DidStartClient() override {
bool ok = IPCTestBase::DidStartClient();
DCHECK(ok);
- host_->OnClientLaunched(client_process());
+ host_->OnClientLaunched(client_process().Handle());
return ok;
}
@@ -226,11 +261,13 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) {
base::MessageLoop::current()->Run();
+ client.Close();
+
return 0;
}
TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) {
- Init("IPCChannelMojoErraticTestClient");
+ InitWithMojo("IPCChannelMojoErraticTestClient");
// Set up IPC channel and start client.
ListenerExpectingErrors listener;
@@ -257,23 +294,281 @@ TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) {
DestroyChannel();
}
+struct TestingMessagePipe {
+ TestingMessagePipe() {
+ EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateMessagePipe(nullptr, &self, &peer));
+ }
+
+ mojo::ScopedMessagePipeHandle self;
+ mojo::ScopedMessagePipeHandle peer;
+};
+
+class HandleSendingHelper {
+ public:
+ static std::string GetSendingFileContent() { return "Hello"; }
+
+ static void WritePipe(IPC::Message* message, TestingMessagePipe* pipe) {
+ std::string content = HandleSendingHelper::GetSendingFileContent();
+ EXPECT_EQ(MOJO_RESULT_OK,
+ mojo::WriteMessageRaw(pipe->self.get(), &content[0],
+ static_cast<uint32_t>(content.size()),
+ nullptr, 0, 0));
+ EXPECT_TRUE(
+ IPC::MojoMessageHelper::WriteMessagePipeTo(message, pipe->peer.Pass()));
+ }
+
+ static void WritePipeThenSend(IPC::Sender* sender, TestingMessagePipe* pipe) {
+ IPC::Message* message =
+ new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+ WritePipe(message, pipe);
+ ASSERT_TRUE(sender->Send(message));
+ }
+
+ static void ReadReceivedPipe(const IPC::Message& message,
+ PickleIterator* iter) {
+ mojo::ScopedMessagePipeHandle pipe;
+ EXPECT_TRUE(
+ IPC::MojoMessageHelper::ReadMessagePipeFrom(&message, iter, &pipe));
+ std::string content(GetSendingFileContent().size(), ' ');
+
+ uint32_t num_bytes = static_cast<uint32_t>(content.size());
+ EXPECT_EQ(MOJO_RESULT_OK,
+ mojo::ReadMessageRaw(pipe.get(), &content[0], &num_bytes, nullptr,
+ nullptr, 0));
+ EXPECT_EQ(content, GetSendingFileContent());
+ }
+
+#if defined(OS_POSIX)
+ static base::FilePath GetSendingFilePath() {
+ base::FilePath path;
+ bool ok = PathService::Get(base::DIR_CACHE, &path);
+ EXPECT_TRUE(ok);
+ return path.Append("ListenerThatExpectsFile.txt");
+ }
+
+ static void WriteFile(IPC::Message* message, base::File& file) {
+ std::string content = GetSendingFileContent();
+ file.WriteAtCurrentPos(content.data(), content.size());
+ file.Flush();
+ message->WriteAttachment(new IPC::internal::PlatformFileAttachment(
+ base::ScopedFD(file.TakePlatformFile())));
+ }
+
+ static void WriteFileThenSend(IPC::Sender* sender, base::File& file) {
+ IPC::Message* message =
+ new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+ WriteFile(message, file);
+ ASSERT_TRUE(sender->Send(message));
+ }
+
+ static void WriteFileAndPipeThenSend(IPC::Sender* sender,
+ base::File& file,
+ TestingMessagePipe* pipe) {
+ IPC::Message* message =
+ new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+ WriteFile(message, file);
+ WritePipe(message, pipe);
+ ASSERT_TRUE(sender->Send(message));
+ }
+
+ static void ReadReceivedFile(const IPC::Message& message,
+ PickleIterator* iter) {
+ base::ScopedFD fd;
+ scoped_refptr<IPC::MessageAttachment> attachment;
+ EXPECT_TRUE(message.ReadAttachment(iter, &attachment));
+ base::File file(attachment->TakePlatformFile());
+ std::string content(GetSendingFileContent().size(), ' ');
+ file.Read(0, &content[0], content.size());
+ EXPECT_EQ(content, GetSendingFileContent());
+ }
+#endif
+};
+
+class ListenerThatExpectsMessagePipe : public IPC::Listener {
+ public:
+ ListenerThatExpectsMessagePipe() : sender_(NULL) {}
+
+ ~ListenerThatExpectsMessagePipe() override {}
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ PickleIterator iter(message);
+ HandleSendingHelper::ReadReceivedPipe(message, &iter);
+ base::MessageLoop::current()->Quit();
+ ListenerThatExpectsOK::SendOK(sender_);
+ return true;
+ }
+
+ void OnChannelError() override { NOTREACHED(); }
+
+ void set_sender(IPC::Sender* sender) { sender_ = sender; }
+
+ private:
+ IPC::Sender* sender_;
+};
+
+TEST_F(IPCChannelMojoTest, SendMessagePipe) {
+ InitWithMojo("IPCChannelMojoTestSendMessagePipeClient");
+
+ ListenerThatExpectsOK listener;
+ CreateChannel(&listener);
+ ASSERT_TRUE(ConnectChannel());
+ ASSERT_TRUE(StartClient());
+
+ TestingMessagePipe pipe;
+ HandleSendingHelper::WritePipeThenSend(channel(), &pipe);
+
+ base::MessageLoop::current()->Run();
+ this->channel()->Close();
+
+ EXPECT_TRUE(WaitForClientShutdown());
+ DestroyChannel();
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendMessagePipeClient) {
+ ListenerThatExpectsMessagePipe listener;
+ ChannelClient client(&listener, "IPCChannelMojoTestSendMessagePipeClient");
+ client.Connect();
+ listener.set_sender(client.channel());
+
+ base::MessageLoop::current()->Run();
+
+ client.Close();
+
+ return 0;
+}
+
+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::ReadMessageRaw(pipe, &should_be_ok[0], &num_bytes, nullptr,
+ nullptr, 0));
+ EXPECT_EQ(should_be_ok, std::string("OK"));
+}
+
+void WriteOK(mojo::MessagePipeHandle pipe) {
+ std::string ok("OK");
+ CHECK_EQ(MOJO_RESULT_OK,
+ mojo::WriteMessageRaw(pipe, &ok[0], static_cast<uint32_t>(ok.size()),
+ nullptr, 0, 0));
+}
+
+class ListenerThatExpectsMessagePipeUsingParamTrait : public IPC::Listener {
+ public:
+ explicit ListenerThatExpectsMessagePipeUsingParamTrait(bool receiving_valid)
+ : sender_(NULL), receiving_valid_(receiving_valid) {}
+
+ ~ListenerThatExpectsMessagePipeUsingParamTrait() override {}
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ PickleIterator iter(message);
+ mojo::MessagePipeHandle handle;
+ EXPECT_TRUE(IPC::ParamTraits<mojo::MessagePipeHandle>::Read(&message, &iter,
+ &handle));
+ EXPECT_EQ(handle.is_valid(), receiving_valid_);
+ if (receiving_valid_) {
+ ReadOK(handle);
+ MojoClose(handle.value());
+ }
+
+ base::MessageLoop::current()->Quit();
+ ListenerThatExpectsOK::SendOK(sender_);
+ return true;
+ }
+
+ void OnChannelError() override { NOTREACHED(); }
+ void set_sender(IPC::Sender* sender) { sender_ = sender; }
+
+ private:
+ IPC::Sender* sender_;
+ 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());
+
+ base::MessageLoop::current()->Run();
+
+ client.Close();
+}
+
+TEST_F(IPCChannelMojoTest, ParamTraitValidMessagePipe) {
+ InitWithMojo("ParamTraitValidMessagePipeClient");
+
+ ListenerThatExpectsOK listener;
+ CreateChannel(&listener);
+ ASSERT_TRUE(ConnectChannel());
+ ASSERT_TRUE(StartClient());
+
+ TestingMessagePipe pipe;
+
+ scoped_ptr<IPC::Message> message(new IPC::Message());
+ IPC::ParamTraits<mojo::MessagePipeHandle>::Write(message.get(),
+ pipe.peer.release());
+ WriteOK(pipe.self.get());
+
+ this->channel()->Send(message.release());
+ base::MessageLoop::current()->Run();
+ this->channel()->Close();
+
+ EXPECT_TRUE(WaitForClientShutdown());
+ DestroyChannel();
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ParamTraitValidMessagePipeClient) {
+ ParamTraitMessagePipeClient(true, "ParamTraitValidMessagePipeClient");
+ return 0;
+}
+
+TEST_F(IPCChannelMojoTest, ParamTraitInvalidMessagePipe) {
+ InitWithMojo("ParamTraitInvalidMessagePipeClient");
+
+ 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());
+ base::MessageLoop::current()->Run();
+ this->channel()->Close();
+
+ EXPECT_TRUE(WaitForClientShutdown());
+ DestroyChannel();
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ParamTraitInvalidMessagePipeClient) {
+ ParamTraitMessagePipeClient(false, "ParamTraitInvalidMessagePipeClient");
+ return 0;
+}
+
#if defined(OS_WIN)
-class IPCChannelMojoDeadHandleTest : public IPCTestBase {
+class IPCChannelMojoDeadHandleTest : public IPCChannelMojoTestBase {
protected:
- virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
+ scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
const IPC::ChannelHandle& handle,
- base::TaskRunner* runner) override {
+ base::SequencedTaskRunner* runner) override {
host_.reset(new IPC::ChannelMojoHost(task_runner()));
return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
- handle);
+ task_runner(), handle);
}
- virtual bool DidStartClient() override {
+ bool DidStartClient() override {
IPCTestBase::DidStartClient();
- base::ProcessHandle client = client_process();
+ const base::ProcessHandle client = client_process().Handle();
// Forces GetFileHandleForProcess() fail. It happens occasionally
// in production, so we should exercise it somehow.
- ::CloseHandle(client);
+ // TODO(morrita): figure out how to safely test this. See crbug.com/464109.
+ // ::CloseHandle(client);
host_->OnClientLaunched(client);
return true;
}
@@ -284,7 +579,7 @@ class IPCChannelMojoDeadHandleTest : public IPCTestBase {
TEST_F(IPCChannelMojoDeadHandleTest, InvalidClientHandle) {
// Any client type is fine as it is going to be killed anyway.
- Init("IPCChannelMojoTestDoNothingClient");
+ InitWithMojo("IPCChannelMojoTestDoNothingClient");
// Set up IPC channel and start client.
ListenerExpectingErrors listener;
@@ -296,9 +591,11 @@ TEST_F(IPCChannelMojoDeadHandleTest, InvalidClientHandle) {
this->channel()->Close();
- // WaitForClientShutdown() fails as client_hanadle() is already
- // closed.
- EXPECT_FALSE(WaitForClientShutdown());
+ // 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();
@@ -326,13 +623,7 @@ class ListenerThatExpectsFile : public IPC::Listener {
bool OnMessageReceived(const IPC::Message& message) override {
PickleIterator iter(message);
-
- base::ScopedFD fd;
- EXPECT_TRUE(message.ReadFile(&iter, &fd));
- base::File file(fd.release());
- std::string content(GetSendingFileContent().size(), ' ');
- file.Read(0, &content[0], content.size());
- EXPECT_EQ(content, GetSendingFileContent());
+ HandleSendingHelper::ReadReceivedFile(message, &iter);
base::MessageLoop::current()->Quit();
ListenerThatExpectsOK::SendOK(sender_);
return true;
@@ -342,27 +633,6 @@ class ListenerThatExpectsFile : public IPC::Listener {
NOTREACHED();
}
- static std::string GetSendingFileContent() {
- return "Hello";
- }
-
- static base::FilePath GetSendingFilePath() {
- base::FilePath path;
- bool ok = PathService::Get(base::DIR_CACHE, &path);
- EXPECT_TRUE(ok);
- return path.Append("ListenerThatExpectsFile.txt");
- }
-
- static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
- std::string content = GetSendingFileContent();
- file.WriteAtCurrentPos(content.data(), content.size());
- file.Flush();
- IPC::Message* message = new IPC::Message(
- 0, 2, IPC::Message::PRIORITY_NORMAL);
- message->WriteFile(base::ScopedFD(file.TakePlatformFile()));
- ASSERT_TRUE(sender->Send(message));
- }
-
void set_sender(IPC::Sender* sender) { sender_ = sender; }
private:
@@ -371,17 +641,17 @@ class ListenerThatExpectsFile : public IPC::Listener {
TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
- Init("IPCChannelMojoTestSendPlatformHandleClient");
+ InitWithMojo("IPCChannelMojoTestSendPlatformHandleClient");
ListenerThatExpectsOK listener;
CreateChannel(&listener);
ASSERT_TRUE(ConnectChannel());
ASSERT_TRUE(StartClient());
- base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
+ base::File file(HandleSendingHelper::GetSendingFilePath(),
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
- base::File::FLAG_READ);
- ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
+ base::File::FLAG_READ);
+ HandleSendingHelper::WriteFileThenSend(channel(), file);
base::MessageLoop::current()->Run();
this->channel()->Close();
@@ -399,8 +669,118 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
base::MessageLoop::current()->Run();
+ client.Close();
+
return 0;
}
+
+class ListenerThatExpectsFileAndPipe : public IPC::Listener {
+ public:
+ ListenerThatExpectsFileAndPipe() : sender_(NULL) {}
+
+ ~ListenerThatExpectsFileAndPipe() override {}
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ PickleIterator iter(message);
+ HandleSendingHelper::ReadReceivedFile(message, &iter);
+ HandleSendingHelper::ReadReceivedPipe(message, &iter);
+ base::MessageLoop::current()->Quit();
+ ListenerThatExpectsOK::SendOK(sender_);
+ return true;
+ }
+
+ void OnChannelError() override { NOTREACHED(); }
+
+ void set_sender(IPC::Sender* sender) { sender_ = sender; }
+
+ private:
+ IPC::Sender* sender_;
+};
+
+TEST_F(IPCChannelMojoTest, SendPlatformHandleAndPipe) {
+ InitWithMojo("IPCChannelMojoTestSendPlatformHandleAndPipeClient");
+
+ ListenerThatExpectsOK listener;
+ CreateChannel(&listener);
+ ASSERT_TRUE(ConnectChannel());
+ ASSERT_TRUE(StartClient());
+
+ base::File file(HandleSendingHelper::GetSendingFilePath(),
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
+ base::File::FLAG_READ);
+ TestingMessagePipe pipe;
+ HandleSendingHelper::WriteFileAndPipeThenSend(channel(), file, &pipe);
+
+ base::MessageLoop::current()->Run();
+ this->channel()->Close();
+
+ EXPECT_TRUE(WaitForClientShutdown());
+ DestroyChannel();
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
+ IPCChannelMojoTestSendPlatformHandleAndPipeClient) {
+ ListenerThatExpectsFileAndPipe listener;
+ ChannelClient client(&listener,
+ "IPCChannelMojoTestSendPlatformHandleAndPipeClient");
+ client.Connect();
+ listener.set_sender(client.channel());
+
+ base::MessageLoop::current()->Run();
+
+ client.Close();
+
+ return 0;
+}
+
#endif
+#if defined(OS_LINUX)
+
+const base::ProcessId kMagicChildId = 54321;
+
+class ListenerThatVerifiesPeerPid : public IPC::Listener {
+ public:
+ void OnChannelConnected(int32 peer_pid) override {
+ EXPECT_EQ(peer_pid, kMagicChildId);
+ base::MessageLoop::current()->Quit();
+ }
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ NOTREACHED();
+ return true;
+ }
+};
+
+TEST_F(IPCChannelMojoTest, VerifyGlobalPid) {
+ InitWithMojo("IPCChannelMojoTestVerifyGlobalPidClient");
+
+ ListenerThatVerifiesPeerPid listener;
+ CreateChannel(&listener);
+ ASSERT_TRUE(ConnectChannel());
+ ASSERT_TRUE(StartClient());
+
+ base::MessageLoop::current()->Run();
+ channel()->Close();
+
+ EXPECT_TRUE(WaitForClientShutdown());
+ DestroyChannel();
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestVerifyGlobalPidClient) {
+ IPC::Channel::SetGlobalPid(kMagicChildId);
+ ListenerThatQuits listener;
+ ChannelClient client(&listener,
+ "IPCChannelMojoTestVerifyGlobalPidClient");
+ client.Connect();
+
+ base::MessageLoop::current()->Run();
+
+ client.Close();
+
+ return 0;
+}
+
+#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 b0df9976b3c..35ba7fd6397 100644
--- a/chromium/ipc/mojo/ipc_message_pipe_reader.cc
+++ b/chromium/ipc/mojo/ipc_message_pipe_reader.cc
@@ -8,24 +8,34 @@
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "mojo/public/cpp/environment/environment.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"
namespace IPC {
namespace internal {
-MessagePipeReader::MessagePipeReader(mojo::ScopedMessagePipeHandle handle)
- : pipe_wait_id_(0),
- pipe_(handle.Pass()) {
- StartWaiting();
+MessagePipeReader::MessagePipeReader(mojo::ScopedMessagePipeHandle handle,
+ MessagePipeReader::Delegate* delegate)
+ : pipe_(handle.Pass()),
+ delegate_(delegate),
+ async_waiter_(
+ new AsyncHandleWaiter(base::Bind(&MessagePipeReader::PipeIsReady,
+ base::Unretained(this)))),
+ pending_send_error_(MOJO_RESULT_OK) {
}
MessagePipeReader::~MessagePipeReader() {
+ // The pipe should be closed before deletion.
CHECK(!IsValid());
+ DCHECK_EQ(pending_send_error_, MOJO_RESULT_OK);
}
void MessagePipeReader::Close() {
- StopWaiting();
+ // All pending errors should be signaled before Close().
+ DCHECK_EQ(pending_send_error_, MOJO_RESULT_OK);
+ async_waiter_.reset();
pipe_.reset();
OnPipeClosed();
}
@@ -35,73 +45,76 @@ void MessagePipeReader::CloseWithError(MojoResult error) {
Close();
}
-// static
-void MessagePipeReader::InvokePipeIsReady(void* closure, MojoResult result) {
- reinterpret_cast<MessagePipeReader*>(closure)->PipeIsReady(result);
+void MessagePipeReader::CloseWithErrorIfPending() {
+ if (pending_send_error_ == MOJO_RESULT_OK)
+ return;
+ MojoResult error = pending_send_error_;
+ pending_send_error_ = MOJO_RESULT_OK;
+ CloseWithError(error);
+ return;
}
-void MessagePipeReader::StartWaiting() {
- DCHECK(pipe_.is_valid());
- DCHECK(!pipe_wait_id_);
- // Not using MOJO_HANDLE_SIGNAL_WRITABLE here, expecting buffer in
- // MessagePipe.
- //
- // TODO(morrita): Should we re-set the signal when we get new
- // message to send?
- pipe_wait_id_ = mojo::Environment::GetDefaultAsyncWaiter()->AsyncWait(
- pipe_.get().value(),
- MOJO_HANDLE_SIGNAL_READABLE,
- MOJO_DEADLINE_INDEFINITE,
- &InvokePipeIsReady,
- this);
+void MessagePipeReader::CloseWithErrorLater(MojoResult error) {
+ pending_send_error_ = error;
}
-void MessagePipeReader::StopWaiting() {
- if (!pipe_wait_id_)
- return;
- mojo::Environment::GetDefaultAsyncWaiter()->CancelWait(pipe_wait_id_);
- pipe_wait_id_ = 0;
-}
+bool MessagePipeReader::Send(scoped_ptr<Message> message) {
+ DCHECK(IsValid());
+
+ message->TraceMessageBegin();
+ std::vector<MojoHandle> handles;
+ MojoResult result = MOJO_RESULT_OK;
+ result = ChannelMojo::ReadFromMessageAttachmentSet(message.get(), &handles);
+ if (result == MOJO_RESULT_OK) {
+ result = MojoWriteMessage(handle(),
+ message->data(),
+ static_cast<uint32>(message->size()),
+ handles.empty() ? nullptr : &handles[0],
+ static_cast<uint32>(handles.size()),
+ MOJO_WRITE_MESSAGE_FLAG_NONE);
+ }
-void MessagePipeReader::PipeIsReady(MojoResult wait_result) {
- pipe_wait_id_ = 0;
+ 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);
+ return false;
+ }
- 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.
- DLOG_IF(WARNING, wait_result != MOJO_RESULT_FAILED_PRECONDITION)
- << "Pipe got error from the waiter. Closing: "
- << wait_result;
- OnPipeError(wait_result);
- }
+ return true;
+}
- Close();
+void MessagePipeReader::OnMessageReceived() {
+ Message message(data_buffer().empty() ? "" : &data_buffer()[0],
+ static_cast<uint32>(data_buffer().size()));
+
+ std::vector<MojoHandle> handle_buffer;
+ TakeHandleBuffer(&handle_buffer);
+ MojoResult write_result =
+ ChannelMojo::WriteToMessageAttachmentSet(handle_buffer, &message);
+ if (write_result != MOJO_RESULT_OK) {
+ CloseWithError(write_result);
return;
}
- while (pipe_.is_valid()) {
- MojoResult read_result = ReadMessageBytes();
- if (read_result == MOJO_RESULT_SHOULD_WAIT)
- break;
- if (read_result != MOJO_RESULT_OK) {
- // FAILED_PRECONDITION means that all the received messages
- // got consumed and the peer is already closed.
- if (read_result != MOJO_RESULT_FAILED_PRECONDITION) {
- DLOG(WARNING)
- << "Pipe got error from ReadMessage(). Closing: " << read_result;
- OnPipeError(read_result);
- }
-
- Close();
- break;
- }
+ message.TraceMessageEnd();
+ delegate_->OnMessageReceived(message);
+}
- OnMessageReceived();
- }
+void MessagePipeReader::OnPipeClosed() {
+ if (!delegate_)
+ return;
+ delegate_->OnPipeClosed(this);
+ delegate_ = nullptr;
+}
- if (pipe_.is_valid())
- StartWaiting();
+void MessagePipeReader::OnPipeError(MojoResult error) {
+ if (!delegate_)
+ return;
+ delegate_->OnPipeError(this);
}
MojoResult MessagePipeReader::ReadMessageBytes() {
@@ -110,9 +123,9 @@ MojoResult MessagePipeReader::ReadMessageBytes() {
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] : NULL,
+ num_bytes ? &data_buffer_[0] : nullptr,
&num_bytes,
- NULL,
+ nullptr,
&num_handles,
MOJO_READ_MESSAGE_FLAG_NONE);
data_buffer_.resize(num_bytes);
@@ -121,9 +134,9 @@ MojoResult MessagePipeReader::ReadMessageBytes() {
// 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] : NULL,
+ num_bytes ? &data_buffer_[0] : nullptr,
&num_bytes,
- num_handles ? &handle_buffer_[0] : NULL,
+ num_handles ? &handle_buffer_[0] : nullptr,
&num_handles,
MOJO_READ_MESSAGE_FLAG_NONE);
}
@@ -133,11 +146,84 @@ MojoResult MessagePipeReader::ReadMessageBytes() {
return result;
}
+void MessagePipeReader::ReadAvailableMessages() {
+ while (pipe_.is_valid()) {
+ MojoResult read_result = ReadMessageBytes();
+ if (read_result == MOJO_RESULT_SHOULD_WAIT)
+ break;
+ if (read_result != MOJO_RESULT_OK) {
+ // FAILED_PRECONDITION means that all the received messages
+ // got consumed and the peer is already closed.
+ if (read_result != MOJO_RESULT_FAILED_PRECONDITION) {
+ DLOG(WARNING)
+ << "Pipe got error from ReadMessage(). Closing: " << read_result;
+ OnPipeError(read_result);
+ }
+
+ Close();
+ break;
+ }
+
+ OnMessageReceived();
+ }
+
+}
+
+void MessagePipeReader::ReadMessagesThenWait() {
+ 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) {
+ 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();
+}
+
void MessagePipeReader::DelayedDeleter::operator()(
MessagePipeReader* ptr) const {
ptr->Close();
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE, base::Bind(&DeleteNow, ptr));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(&DeleteNow, ptr));
}
} // namespace internal
diff --git a/chromium/ipc/mojo/ipc_message_pipe_reader.h b/chromium/ipc/mojo/ipc_message_pipe_reader.h
index ecfa018b5e0..937930eef33 100644
--- a/chromium/ipc/mojo/ipc_message_pipe_reader.h
+++ b/chromium/ipc/mojo/ipc_message_pipe_reader.h
@@ -7,13 +7,17 @@
#include <vector>
+#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "mojo/public/c/environment/async_waiter.h"
-#include "mojo/public/cpp/system/core.h"
+#include "ipc/ipc_message.h"
+#include "third_party/mojo/src/mojo/public/c/environment/async_waiter.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/core.h"
namespace IPC {
namespace internal {
+class AsyncHandleWaiter;
+
// A helper class to handle bytestream directly over mojo::MessagePipe
// in template-method pattern. MessagePipeReader manages the lifetime
// of given MessagePipe and participates the event loop, and
@@ -30,6 +34,13 @@ namespace internal {
//
class MessagePipeReader {
public:
+ class Delegate {
+ public:
+ virtual void OnMessageReceived(Message& message) = 0;
+ virtual void OnPipeClosed(MessagePipeReader* reader) = 0;
+ virtual void OnPipeError(MessagePipeReader* reader) = 0;
+ };
+
// Delay the object deletion using the current message loop.
// This is intended to used by MessagePipeReader owners.
class DelayedDeleter {
@@ -39,13 +50,16 @@ class MessagePipeReader {
static void DeleteNow(MessagePipeReader* ptr) { delete ptr; }
DelayedDeleter() {}
- DelayedDeleter(const DefaultType&) {}
+ explicit DelayedDeleter(const DefaultType&) {}
DelayedDeleter& operator=(const DefaultType&) { return *this; }
void operator()(MessagePipeReader* ptr) const;
};
- explicit MessagePipeReader(mojo::ScopedMessagePipeHandle handle);
+ // 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 pipe_.get().value(); }
@@ -65,29 +79,31 @@ class MessagePipeReader {
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(); }
- //
- // The client have to implment these callback to get the readiness
- // event from the reader
- //
- virtual void OnMessageReceived() = 0;
- virtual void OnPipeClosed() = 0;
- virtual void OnPipeError(MojoResult error) = 0;
+ bool Send(scoped_ptr<Message> message);
+ void ReadMessagesThenWait();
private:
- static void InvokePipeIsReady(void* closure, MojoResult result);
+ void OnMessageReceived();
+ void OnPipeClosed();
+ void OnPipeError(MojoResult error);
MojoResult ReadMessageBytes();
void PipeIsReady(MojoResult wait_result);
- void StartWaiting();
- void StopWaiting();
+ void ReadAvailableMessages();
std::vector<char> data_buffer_;
std::vector<MojoHandle> handle_buffer_;
- MojoAsyncWaitID pipe_wait_id_;
mojo::ScopedMessagePipeHandle pipe_;
+ // |delegate_| and |async_waiter_| are null once the message pipe is closed.
+ Delegate* delegate_;
+ scoped_ptr<AsyncHandleWaiter> async_waiter_;
+ MojoResult pending_send_error_;
DISALLOW_COPY_AND_ASSIGN(MessagePipeReader);
};
diff --git a/chromium/ipc/mojo/ipc_mojo.gyp b/chromium/ipc/mojo/ipc_mojo.gyp
index a9a26737828..a392283263d 100644
--- a/chromium/ipc/mojo/ipc_mojo.gyp
+++ b/chromium/ipc/mojo/ipc_mojo.gyp
@@ -17,27 +17,35 @@
'defines': [
'IPC_MOJO_IMPLEMENTATION',
],
- 'includes': [ '../../mojo/public/tools/bindings/mojom_bindings_generator.gypi' ],
+ 'includes': [ '../../third_party/mojo/mojom_bindings_generator.gypi' ],
'dependencies': [
'../ipc.gyp:ipc',
'../../base/base.gyp:base',
'../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../../mojo/edk/mojo_edk.gyp:mojo_system_impl',
'../../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
+ '../../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
+ '../../third_party/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_channel_mojo_host.cc',
'ipc_channel_mojo_host.h',
- 'ipc_channel_mojo_readers.cc',
- 'ipc_channel_mojo_readers.h',
'ipc_mojo_bootstrap.cc',
'ipc_mojo_bootstrap.h',
+ 'ipc_mojo_handle_attachment.cc',
+ 'ipc_mojo_handle_attachment.h',
+ 'ipc_mojo_message_helper.cc',
+ 'ipc_mojo_message_helper.h',
+ 'ipc_mojo_param_traits.cc',
+ 'ipc_mojo_param_traits.h',
'ipc_message_pipe_reader.cc',
'ipc_message_pipe_reader.h',
+ 'scoped_ipc_support.cc',
+ 'scoped_ipc_support.h',
],
# TODO(gregoryd): direct_dependent_settings should be shared with the
# 64-bit target, but it doesn't work due to a bug in gyp
@@ -56,16 +64,17 @@
'../../base/base.gyp:base',
'../../base/base.gyp:base_i18n',
'../../base/base.gyp:test_support_base',
- '../../mojo/edk/mojo_edk.gyp:mojo_system_impl',
'../../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../../mojo/public/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_mojo_bootstrap_unittest.cc',
@@ -83,10 +92,10 @@
'../../base/base.gyp:base_i18n',
'../../base/base.gyp:test_support_base',
'../../base/base.gyp:test_support_perf',
- '../../mojo/edk/mojo_edk.gyp:mojo_system_impl',
'../../mojo/mojo_base.gyp:mojo_environment_chromium',
- '../../mojo/public/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 4af4e503a9d..d307246033f 100644
--- a/chromium/ipc/mojo/ipc_mojo_bootstrap.cc
+++ b/chromium/ipc/mojo/ipc_mojo_bootstrap.cc
@@ -8,7 +8,7 @@
#include "base/process/process_handle.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_platform_file.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
namespace IPC {
@@ -61,7 +61,7 @@ void MojoServerBootstrap::SendClientPipe() {
// GetFileHandleForProcess() only fails on Windows.
NOTREACHED();
#endif
- DLOG(WARNING) << "Failed to translate file handle for client process.";
+ LOG(WARNING) << "Failed to translate file handle for client process.";
Fail();
return;
}
@@ -100,9 +100,14 @@ void MojoServerBootstrap::OnChannelConnected(int32 peer_pid) {
}
bool MojoServerBootstrap::OnMessageReceived(const Message&) {
- DCHECK_EQ(state(), STATE_WAITING_ACK);
- set_state(STATE_READY);
+ if (state() != STATE_WAITING_ACK) {
+ set_state(STATE_ERROR);
+ LOG(ERROR) << "Got inconsistent message from client.";
+ return false;
+ }
+ set_state(STATE_READY);
+ CHECK(server_pipe_.is_valid());
delegate()->OnPipeAvailable(
mojo::embedder::ScopedPlatformHandle(server_pipe_.release()));
@@ -129,10 +134,16 @@ MojoClientBootstrap::MojoClientBootstrap() {
}
bool MojoClientBootstrap::OnMessageReceived(const Message& message) {
+ if (state() != STATE_INITIALIZED) {
+ set_state(STATE_ERROR);
+ LOG(ERROR) << "Got inconsistent message from server.";
+ return false;
+ }
+
PlatformFileForTransit pipe;
PickleIterator iter(message);
if (!ParamTraits<PlatformFileForTransit>::Read(&message, &iter, &pipe)) {
- DLOG(WARNING) << "Failed to read a file handle from bootstrap channel.";
+ LOG(WARNING) << "Failed to read a file handle from bootstrap channel.";
message.set_dispatch_error();
return false;
}
@@ -189,6 +200,10 @@ bool MojoBootstrap::Connect() {
return channel_->Connect();
}
+base::ProcessId MojoBootstrap::GetSelfPID() const {
+ return channel_->GetSelfPID();
+}
+
void MojoBootstrap::OnBadMessageReceived(const Message& message) {
Fail();
}
diff --git a/chromium/ipc/mojo/ipc_mojo_bootstrap.h b/chromium/ipc/mojo/ipc_mojo_bootstrap.h
index ad5283d96ca..1f71d2e6d4f 100644
--- a/chromium/ipc/mojo/ipc_mojo_bootstrap.h
+++ b/chromium/ipc/mojo/ipc_mojo_bootstrap.h
@@ -9,7 +9,7 @@
#include "base/process/process_handle.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_listener.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
namespace IPC {
@@ -46,6 +46,9 @@ class IPC_MOJO_EXPORT MojoBootstrap : public Listener {
// Start the handshake over the underlying platform channel.
bool Connect();
+ // GetSelfPID returns the PID associated with |channel_|.
+ base::ProcessId GetSelfPID() const;
+
// Each client should call this once the process handle becomes known.
virtual void OnClientLaunched(base::ProcessHandle process) = 0;
@@ -55,6 +58,9 @@ class IPC_MOJO_EXPORT MojoBootstrap : public Listener {
#endif // defined(OS_POSIX) && !defined(OS_NACL)
protected:
+ // On MojoServerBootstrap: INITIALIZED -> WAITING_ACK -> READY
+ // On MojoClientBootstrap: INITIALIZED -> READY
+ // STATE_ERROR is a catch-all state that captures any observed error.
enum State { STATE_INITIALIZED, STATE_WAITING_ACK, STATE_READY, STATE_ERROR };
Delegate* delegate() const { return delegate_; }
diff --git a/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc b/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc
index a071d66a7e8..fbe0fa89589 100644
--- a/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc
+++ b/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc
@@ -55,7 +55,7 @@ TEST_F(IPCMojoBootstrapTest, Connect) {
#else
ASSERT_TRUE(StartClient());
#endif
- bootstrap->OnClientLaunched(client_process());
+ bootstrap->OnClientLaunched(client_process().Handle());
base::MessageLoop::current()->Run();
diff --git a/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc b/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc
new file mode 100644
index 00000000000..98ac5c3c5e0
--- /dev/null
+++ b/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 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/ipc_mojo_handle_attachment.h"
+
+#include "ipc/ipc_message_attachment_set.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+
+namespace IPC {
+namespace internal {
+
+MojoHandleAttachment::MojoHandleAttachment(mojo::ScopedHandle handle)
+ : handle_(handle.Pass()) {
+}
+
+MojoHandleAttachment::~MojoHandleAttachment() {
+}
+
+MessageAttachment::Type MojoHandleAttachment::GetType() const {
+ return TYPE_MOJO_HANDLE;
+}
+
+#if defined(OS_POSIX)
+base::PlatformFile MojoHandleAttachment::TakePlatformFile() {
+ mojo::embedder::ScopedPlatformHandle platform_handle;
+ MojoResult unwrap_result = mojo::embedder::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;
+}
+#endif // OS_POSIX
+
+mojo::ScopedHandle MojoHandleAttachment::TakeHandle() {
+ return handle_.Pass();
+}
+
+} // namespace internal
+} // namespace IPC
diff --git a/chromium/ipc/mojo/ipc_mojo_handle_attachment.h b/chromium/ipc/mojo/ipc_mojo_handle_attachment.h
new file mode 100644
index 00000000000..ef5a318ec72
--- /dev/null
+++ b/chromium/ipc/mojo/ipc_mojo_handle_attachment.h
@@ -0,0 +1,50 @@
+// Copyright (c) 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_IPC_MOJO_HANDLE_ATTACHMENT_H_
+#define IPC_MOJO_IPC_MOJO_HANDLE_ATTACHMENT_H_
+
+#include "base/files/file.h"
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_message_attachment.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/handle.h"
+
+namespace IPC {
+
+namespace internal {
+
+// A MessageAttachment that holds a MojoHandle.
+// * On the sending side, every Mojo handle is a MessagePipe. This is because
+// any platform files are wrapped by PlatformFileAttachment.
+// * On the receiving side, the handle can be either MessagePipe or wrapped
+// platform file: All files, not only MessagePipes are wrapped as a
+// MojoHandle. The message deserializer should know which type of the object
+// the handle wraps.
+class IPC_MOJO_EXPORT MojoHandleAttachment : public MessageAttachment {
+ public:
+ explicit MojoHandleAttachment(mojo::ScopedHandle handle);
+
+ Type GetType() const override;
+
+#if defined(OS_POSIX)
+ // Returns wrapped file if it wraps a file, or
+ // an invalid fd otherwise. The ownership of handle
+ // is passed to the caller.
+ base::PlatformFile TakePlatformFile() override;
+#endif // OS_POSIX
+
+ // Returns the owning handle transferring the ownership.
+ mojo::ScopedHandle TakeHandle();
+
+ private:
+ ~MojoHandleAttachment() override;
+ mojo::ScopedHandle handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoHandleAttachment);
+};
+
+} // namespace internal
+} // namespace IPC
+
+#endif // IPC_MOJO_IPC_MOJO_HANDLE_ATTACHMENT_H_
diff --git a/chromium/ipc/mojo/ipc_mojo_message_helper.cc b/chromium/ipc/mojo/ipc_mojo_message_helper.cc
new file mode 100644
index 00000000000..38b870dde50
--- /dev/null
+++ b/chromium/ipc/mojo/ipc_mojo_message_helper.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 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/ipc_mojo_message_helper.h"
+
+#include "ipc/mojo/ipc_mojo_handle_attachment.h"
+
+namespace IPC {
+
+// static
+bool MojoMessageHelper::WriteMessagePipeTo(
+ Message* message,
+ mojo::ScopedMessagePipeHandle handle) {
+ message->WriteAttachment(new internal::MojoHandleAttachment(
+ mojo::ScopedHandle::From(handle.Pass())));
+ return true;
+}
+
+// static
+bool MojoMessageHelper::ReadMessagePipeFrom(
+ const Message* message,
+ PickleIterator* iter,
+ mojo::ScopedMessagePipeHandle* handle) {
+ scoped_refptr<MessageAttachment> 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();
+ return false;
+ }
+
+ handle->reset(mojo::MessagePipeHandle(
+ static_cast<internal::MojoHandleAttachment*>(attachment.get())
+ ->TakeHandle()
+ .release()
+ .value()));
+ return true;
+}
+
+MojoMessageHelper::MojoMessageHelper() {
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/mojo/ipc_mojo_message_helper.h b/chromium/ipc/mojo/ipc_mojo_message_helper.h
new file mode 100644
index 00000000000..efb48c33a94
--- /dev/null
+++ b/chromium/ipc/mojo/ipc_mojo_message_helper.h
@@ -0,0 +1,29 @@
+// Copyright (c) 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_IPC_MOJO_MESSAGE_HELPER_H_
+#define IPC_MOJO_IPC_MOJO_MESSAGE_HELPER_H_
+
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_message.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
+
+namespace IPC {
+
+// Reads and writes |mojo::MessagePipe| from/to |Message|.
+class IPC_MOJO_EXPORT MojoMessageHelper {
+ public:
+ static bool WriteMessagePipeTo(Message* message,
+ mojo::ScopedMessagePipeHandle handle);
+ static bool ReadMessagePipeFrom(const Message* message,
+ PickleIterator* iter,
+ mojo::ScopedMessagePipeHandle* handle);
+
+ private:
+ MojoMessageHelper();
+};
+
+} // namespace IPC
+
+#endif // IPC_MOJO_IPC_MOJO_MESSAGE_HELPER_H_
diff --git a/chromium/ipc/mojo/ipc_mojo_param_traits.cc b/chromium/ipc/mojo/ipc_mojo_param_traits.cc
new file mode 100644
index 00000000000..80c3ca70c92
--- /dev/null
+++ b/chromium/ipc/mojo/ipc_mojo_param_traits.cc
@@ -0,0 +1,43 @@
+// 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/ipc_mojo_param_traits.h"
+
+#include "ipc/ipc_message_utils.h"
+#include "ipc/mojo/ipc_mojo_message_helper.h"
+
+namespace IPC {
+
+void ParamTraits<mojo::MessagePipeHandle>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.is_valid());
+ if (p.is_valid())
+ MojoMessageHelper::WriteMessagePipeTo(m, mojo::ScopedMessagePipeHandle(p));
+}
+
+bool ParamTraits<mojo::MessagePipeHandle>::Read(const Message* m,
+ PickleIterator* iter,
+ param_type* r) {
+ bool is_valid;
+ if (!ReadParam(m, iter, &is_valid))
+ return false;
+ if (!is_valid)
+ return true;
+
+ mojo::ScopedMessagePipeHandle handle;
+ if (!MojoMessageHelper::ReadMessagePipeFrom(m, iter, &handle))
+ return false;
+ DCHECK(handle.is_valid());
+ *r = handle.release();
+ return true;
+}
+
+void ParamTraits<mojo::MessagePipeHandle>::Log(const param_type& p,
+ std::string* l) {
+ l->append("mojo::MessagePipeHandle(");
+ LogParam(p.value(), l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/mojo/ipc_mojo_param_traits.h b/chromium/ipc/mojo/ipc_mojo_param_traits.h
new file mode 100644
index 00000000000..d12e44fccd8
--- /dev/null
+++ b/chromium/ipc/mojo/ipc_mojo_param_traits.h
@@ -0,0 +1,30 @@
+// 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_IPC_MOJO_PARAM_TRAITS_H_
+#define IPC_MOJO_IPC_MOJO_PARAM_TRAITS_H_
+
+#include <string>
+
+#include "ipc/ipc_export.h"
+#include "ipc/ipc_param_traits.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
+
+class PickleIterator;
+
+namespace IPC {
+
+class Message;
+
+template <>
+struct IPC_MOJO_EXPORT ParamTraits<mojo::MessagePipeHandle> {
+ typedef mojo::MessagePipeHandle param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // IPC_MOJO_IPC_MOJO_PARAM_TRAITS_H_
diff --git a/chromium/ipc/mojo/ipc_mojo_perftest.cc b/chromium/ipc/mojo/ipc_mojo_perftest.cc
index 29e78397ce2..dc96dd19a14 100644
--- a/chromium/ipc/mojo/ipc_mojo_perftest.cc
+++ b/chromium/ipc/mojo/ipc_mojo_perftest.cc
@@ -3,10 +3,11 @@
// found in the LICENSE file.
#include "base/lazy_instance.h"
+#include "base/run_loop.h"
#include "ipc/ipc_perftest_support.h"
#include "ipc/mojo/ipc_channel_mojo.h"
#include "ipc/mojo/ipc_channel_mojo_host.h"
-#include "mojo/edk/embedder/test_embedder.h"
+#include "third_party/mojo/src/mojo/edk/embedder/test_embedder.h"
namespace {
@@ -29,42 +30,46 @@ public:
MojoChannelPerfTest();
+ void TearDown() override {
+ IPC::test::IPCChannelPerfTestBase::TearDown();
+ }
+
scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
const IPC::ChannelHandle& handle,
- base::TaskRunner* runner) override {
- host_.reset(new IPC::ChannelMojoHost(task_runner()));
+ base::SequencedTaskRunner* runner) override {
+ host_.reset(new IPC::ChannelMojoHost(runner));
return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
- handle);
+ runner, handle);
}
bool DidStartClient() override {
bool ok = IPCTestBase::DidStartClient();
DCHECK(ok);
- host_->OnClientLaunched(client_process());
+ host_->OnClientLaunched(client_process().Handle());
return ok;
}
- void set_io_thread_task_runner(base::TaskRunner* runner) {
- io_thread_task_runner_ = runner;
- }
-
private:
- base::TaskRunner* io_thread_task_runner_;
scoped_ptr<IPC::ChannelMojoHost> host_;
};
-MojoChannelPerfTest::MojoChannelPerfTest()
- : io_thread_task_runner_() {
+MojoChannelPerfTest::MojoChannelPerfTest() {
g_mojo_initializer.Get();
}
TEST_F(MojoChannelPerfTest, ChannelPingPong) {
RunTestChannelPingPong(GetDefaultTestParams());
+
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
}
TEST_F(MojoChannelPerfTest, ChannelProxyPingPong) {
RunTestChannelProxyPingPong(GetDefaultTestParams());
+
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
}
class MojoTestClient : public IPC::test::PingPongTestClient {
@@ -82,16 +87,19 @@ MojoTestClient::MojoTestClient() {
scoped_ptr<IPC::Channel> MojoTestClient::CreateChannel(
IPC::Listener* listener) {
- return scoped_ptr<IPC::Channel>(
- IPC::ChannelMojo::Create(NULL,
- IPCTestBase::GetChannelName("PerformanceClient"),
- IPC::Channel::MODE_CLIENT,
- listener));
+ return scoped_ptr<IPC::Channel>(IPC::ChannelMojo::Create(
+ NULL, task_runner(), IPCTestBase::GetChannelName("PerformanceClient"),
+ IPC::Channel::MODE_CLIENT, listener));
}
MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) {
MojoTestClient client;
- return client.RunMain();
+ int rv = client.RunMain();
+
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ return rv;
}
} // namespace
diff --git a/chromium/ipc/mojo/run_all_unittests.cc b/chromium/ipc/mojo/run_all_unittests.cc
index cc5b1028c89..fe2bf85c7a1 100644
--- a/chromium/ipc/mojo/run_all_unittests.cc
+++ b/chromium/ipc/mojo/run_all_unittests.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
-#include "mojo/edk/embedder/test_embedder.h"
+#include "third_party/mojo/src/mojo/edk/embedder/test_embedder.h"
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
diff --git a/chromium/ipc/mojo/scoped_ipc_support.cc b/chromium/ipc/mojo/scoped_ipc_support.cc
new file mode 100644
index 00000000000..b1d530e0463
--- /dev/null
+++ b/chromium/ipc/mojo/scoped_ipc_support.cc
@@ -0,0 +1,178 @@
+// 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/scoped_ipc_support.h"
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.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"
+
+namespace IPC {
+
+namespace {
+
+class IPCSupportInitializer : public mojo::embedder::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();
+
+ // Forces the initializer to shut down even if scopers are still holding it.
+ void ForceShutdown();
+
+ 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_->ForceShutdown();
+ }
+
+ 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_;
+
+ 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);
+ 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, io_thread_task_runner_, this,
+ io_thread_task_runner_, mojo::embedder::ScopedPlatformHandle());
+ }
+}
+
+void IPCSupportInitializer::ShutDown() {
+ {
+ base::AutoLock locker(lock_);
+ if (shutting_down_ || was_shut_down_)
+ return;
+ DCHECK(init_count_ > 0);
+ if (init_count_ > 1) {
+ init_count_--;
+ return;
+ }
+ }
+ ForceShutdown();
+}
+
+void IPCSupportInitializer::ForceShutdown() {
+ base::AutoLock locker(lock_);
+ if (shutting_down_ || was_shut_down_)
+ return;
+ 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 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;
+ }
+ }
+}
+
+// static
+void IPCSupportInitializer::WatchMessageLoopOnIOThread(
+ MessageLoopObserver* observer) {
+ base::MessageLoop::current()->AddDestructionObserver(observer);
+}
+
+base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer;
+
+} // namespace
+
+ScopedIPCSupport::ScopedIPCSupport(
+ scoped_refptr<base::TaskRunner> io_thread_task_runner) {
+ ipc_support_initializer.Get().Init(io_thread_task_runner);
+}
+
+ScopedIPCSupport::~ScopedIPCSupport() {
+ 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
new file mode 100644
index 00000000000..21013fa75c0
--- /dev/null
+++ b/chromium/ipc/mojo/scoped_ipc_support.h
@@ -0,0 +1,34 @@
+// 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_SCOPED_IPC_SUPPORT_H_
+#define IPC_MOJO_SCOPED_IPC_SUPPORT_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "ipc/ipc_export.h"
+
+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.
+//
+// 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.
+class IPC_MOJO_EXPORT ScopedIPCSupport {
+ public:
+ ScopedIPCSupport(scoped_refptr<base::TaskRunner> io_thread_task_runner);
+ ~ScopedIPCSupport();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedIPCSupport);
+};
+
+} // namespace IPC
+
+#endif // IPC_MOJO_SCOPED_IPC_SUPPORT_H_
diff --git a/chromium/ipc/param_traits_read_macros.h b/chromium/ipc/param_traits_read_macros.h
index 1656d14228b..683a1de261c 100644
--- a/chromium/ipc/param_traits_read_macros.h
+++ b/chromium/ipc/param_traits_read_macros.h
@@ -35,7 +35,7 @@
bool ParamTraits<enum_name>:: \
Read(const Message* m, PickleIterator* iter, param_type* p) { \
int value; \
- if (!m->ReadInt(iter, &value)) \
+ if (!iter->ReadInt(&value)) \
return false; \
if (!(validation_expression)) \
return false; \
diff --git a/chromium/ipc/sync_socket_unittest.cc b/chromium/ipc/sync_socket_unittest.cc
index 77ae72d39e3..82ab0cd0992 100644
--- a/chromium/ipc/sync_socket_unittest.cc
+++ b/chromium/ipc/sync_socket_unittest.cc
@@ -5,11 +5,12 @@
#include "base/sync_socket.h"
#include <stdio.h>
-#include <string>
#include <sstream>
+#include <string>
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "ipc/ipc_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -184,7 +185,7 @@ TEST_F(SyncSocketTest, SanityTest) {
#if defined(OS_WIN)
// On windows we need to duplicate the handle into the server process.
BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1].handle(),
- client_process(), &target_handle,
+ client_process().Handle(), &target_handle,
0, FALSE, DUPLICATE_SAME_ACCESS);
EXPECT_TRUE(retval);
// Set up a message to pass the handle to the server.
@@ -227,7 +228,8 @@ TEST_F(SyncSocketTest, DisconnectTest) {
// Try to do a blocking read from one of the sockets on the worker thread.
char buf[0xff];
size_t received = 1U; // Initialize to an unexpected value.
- worker.message_loop()->PostTask(FROM_HERE,
+ worker.task_runner()->PostTask(
+ FROM_HERE,
base::Bind(&BlockingRead, &pair[0], &buf[0], arraysize(buf), &received));
// Wait for the worker thread to say hello.
@@ -257,9 +259,9 @@ TEST_F(SyncSocketTest, BlockingReceiveTest) {
// Try to do a blocking read from one of the sockets on the worker thread.
char buf[kHelloStringLength] = {0};
size_t received = 1U; // Initialize to an unexpected value.
- worker.message_loop()->PostTask(FROM_HERE,
- base::Bind(&BlockingRead, &pair[0], &buf[0],
- kHelloStringLength, &received));
+ worker.task_runner()->PostTask(FROM_HERE,
+ base::Bind(&BlockingRead, &pair[0], &buf[0],
+ kHelloStringLength, &received));
// Wait for the worker thread to say hello.
char hello[kHelloStringLength] = {0};
diff --git a/chromium/ipc/unix_domain_socket_util.cc b/chromium/ipc/unix_domain_socket_util.cc
index d1ddd83e5ce..74053445b7a 100644
--- a/chromium/ipc/unix_domain_socket_util.cc
+++ b/chromium/ipc/unix_domain_socket_util.cc
@@ -20,8 +20,8 @@
namespace IPC {
// Verify that kMaxSocketNameLength is a decent size.
-COMPILE_ASSERT(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxSocketNameLength,
- BAD_SUN_PATH_LENGTH);
+static_assert(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxSocketNameLength,
+ "sun_path is too long.");
namespace {
diff --git a/chromium/ipc/unix_domain_socket_util_unittest.cc b/chromium/ipc/unix_domain_socket_util_unittest.cc
index 813d4979260..57365a5840d 100644
--- a/chromium/ipc/unix_domain_socket_util_unittest.cc
+++ b/chromium/ipc/unix_domain_socket_util_unittest.cc
@@ -6,8 +6,10 @@
#include "base/bind.h"
#include "base/files/file_path.h"
+#include "base/location.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
@@ -18,7 +20,7 @@ namespace {
class SocketAcceptor : public base::MessageLoopForIO::Watcher {
public:
- SocketAcceptor(int fd, base::MessageLoopProxy* target_thread)
+ SocketAcceptor(int fd, base::SingleThreadTaskRunner* target_thread)
: server_fd_(-1),
target_thread_(target_thread),
started_watching_event_(false, false),
@@ -69,7 +71,7 @@ class SocketAcceptor : public base::MessageLoopForIO::Watcher {
void OnFileCanWriteWithoutBlocking(int fd) override {}
int server_fd_;
- base::MessageLoopProxy* target_thread_;
+ base::SingleThreadTaskRunner* target_thread_;
scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> watcher_;
base::WaitableEvent started_watching_event_;
base::WaitableEvent accepted_event_;
@@ -78,13 +80,9 @@ class SocketAcceptor : public base::MessageLoopForIO::Watcher {
};
const base::FilePath GetChannelDir() {
-#if defined(OS_ANDROID)
base::FilePath tmp_dir;
- PathService::Get(base::DIR_CACHE, &tmp_dir);
+ PathService::Get(base::DIR_TEMP, &tmp_dir);
return tmp_dir;
-#else
- return base::FilePath("/var/tmp");
-#endif
}
class TestUnixSocketConnection {
@@ -107,8 +105,8 @@ class TestUnixSocketConnection {
struct stat socket_stat;
stat(socket_name_.value().c_str(), &socket_stat);
EXPECT_TRUE(S_ISSOCK(socket_stat.st_mode));
- acceptor_.reset(new SocketAcceptor(server_listen_fd_,
- worker_.message_loop_proxy().get()));
+ acceptor_.reset(
+ new SocketAcceptor(server_listen_fd_, worker_.task_runner().get()));
acceptor_->WaitUntilReady();
return true;
}