summaryrefslogtreecommitdiff
path: root/chromium/ipc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-01-25 11:39:07 +0100
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2016-01-25 15:20:42 +0000
commit6c91641271e536ffaa88a1dff5127e42ee99a91e (patch)
tree703d9dd49602377ddc90cbf886aad37913f2496b /chromium/ipc
parentb145b7fafd36f0c260d6a768c81fc14e32578099 (diff)
downloadqtwebengine-chromium-6c91641271e536ffaa88a1dff5127e42ee99a91e.tar.gz
BASELINE: Update Chromium to 49.0.2623.23
Also adds missing printing sources. Change-Id: I3726b8f0c7d6751c9fc846096c571fadca7108cd Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/ipc')
-rw-r--r--chromium/ipc/BUILD.gn193
-rw-r--r--chromium/ipc/attachment_broker.cc87
-rw-r--r--chromium/ipc/attachment_broker.h56
-rw-r--r--chromium/ipc/attachment_broker_mac_unittest.cc1335
-rw-r--r--chromium/ipc/attachment_broker_messages.h32
-rw-r--r--chromium/ipc/attachment_broker_privileged.cc103
-rw-r--r--chromium/ipc/attachment_broker_privileged.h61
-rw-r--r--chromium/ipc/attachment_broker_privileged_mac.cc451
-rw-r--r--chromium/ipc/attachment_broker_privileged_mac.h224
-rw-r--r--chromium/ipc/attachment_broker_privileged_mac_unittest.cc435
-rw-r--r--chromium/ipc/attachment_broker_privileged_win.cc62
-rw-r--r--chromium/ipc/attachment_broker_privileged_win.h8
-rw-r--r--chromium/ipc/attachment_broker_privileged_win_unittest.cc180
-rw-r--r--chromium/ipc/attachment_broker_unprivileged.cc31
-rw-r--r--chromium/ipc/attachment_broker_unprivileged.h14
-rw-r--r--chromium/ipc/attachment_broker_unprivileged_mac.cc110
-rw-r--r--chromium/ipc/attachment_broker_unprivileged_mac.h43
-rw-r--r--chromium/ipc/attachment_broker_unprivileged_win.cc11
-rw-r--r--chromium/ipc/attachment_broker_unprivileged_win.h6
-rw-r--r--chromium/ipc/attachment_broker_unprivileged_win_unittest.cc51
-rw-r--r--chromium/ipc/brokerable_attachment.cc3
-rw-r--r--chromium/ipc/brokerable_attachment.h19
-rw-r--r--chromium/ipc/brokerable_attachment_mac.cc22
-rw-r--r--chromium/ipc/handle_attachment_win.cc24
-rw-r--r--chromium/ipc/handle_attachment_win.h21
-rw-r--r--chromium/ipc/handle_win.cc9
-rw-r--r--chromium/ipc/handle_win.h14
-rw-r--r--chromium/ipc/ipc.gyp29
-rw-r--r--chromium/ipc/ipc.gypi5
-rw-r--r--chromium/ipc/ipc_channel.cc2
-rw-r--r--chromium/ipc/ipc_channel.h21
-rw-r--r--chromium/ipc/ipc_channel_common.cc1
-rw-r--r--chromium/ipc/ipc_channel_factory.cc1
-rw-r--r--chromium/ipc/ipc_channel_nacl.cc6
-rw-r--r--chromium/ipc/ipc_channel_nacl.h1
-rw-r--r--chromium/ipc/ipc_channel_posix.cc150
-rw-r--r--chromium/ipc/ipc_channel_posix.h34
-rw-r--r--chromium/ipc/ipc_channel_posix_unittest.cc9
-rw-r--r--chromium/ipc/ipc_channel_proxy.cc17
-rw-r--r--chromium/ipc/ipc_channel_proxy.h5
-rw-r--r--chromium/ipc/ipc_channel_proxy_unittest.cc3
-rw-r--r--chromium/ipc/ipc_channel_reader.cc203
-rw-r--r--chromium/ipc/ipc_channel_reader.h46
-rw-r--r--chromium/ipc/ipc_channel_reader_unittest.cc195
-rw-r--r--chromium/ipc/ipc_channel_unittest.cc2
-rw-r--r--chromium/ipc/ipc_channel_win.cc26
-rw-r--r--chromium/ipc/ipc_channel_win.h1
-rw-r--r--chromium/ipc/ipc_fuzzing_tests.cc5
-rw-r--r--chromium/ipc/ipc_logging.cc4
-rw-r--r--chromium/ipc/ipc_message.cc52
-rw-r--r--chromium/ipc/ipc_message.h5
-rw-r--r--chromium/ipc/ipc_message_attachment.h5
-rw-r--r--chromium/ipc/ipc_message_attachment_set.cc107
-rw-r--r--chromium/ipc/ipc_message_attachment_set.h69
-rw-r--r--chromium/ipc/ipc_message_attachment_set_posix_unittest.cc60
-rw-r--r--chromium/ipc/ipc_message_macros.h2
-rw-r--r--chromium/ipc/ipc_message_start.h9
-rw-r--r--chromium/ipc/ipc_message_unittest.cc4
-rw-r--r--chromium/ipc/ipc_message_utils.cc89
-rw-r--r--chromium/ipc/ipc_message_utils.h26
-rw-r--r--chromium/ipc/ipc_message_utils_unittest.cc1
-rw-r--r--chromium/ipc/ipc_perftest_support.cc5
-rw-r--r--chromium/ipc/ipc_perftest_support.h4
-rw-r--r--chromium/ipc/ipc_platform_file.cc1
-rw-r--r--chromium/ipc/ipc_platform_file.h1
-rw-r--r--chromium/ipc/ipc_platform_file_attachment_posix.cc5
-rw-r--r--chromium/ipc/ipc_send_fds_test.cc5
-rw-r--r--chromium/ipc/ipc_sync_channel.cc23
-rw-r--r--chromium/ipc/ipc_sync_channel_unittest.cc3
-rw-r--r--chromium/ipc/ipc_sync_message.cc2
-rw-r--r--chromium/ipc/ipc_sync_message.h1
-rw-r--r--chromium/ipc/ipc_test_base.cc13
-rw-r--r--chromium/ipc/ipc_test_base.h8
-rw-r--r--chromium/ipc/ipc_test_channel_listener.cc4
-rw-r--r--chromium/ipc/ipc_test_messages.h28
-rw-r--r--chromium/ipc/ipc_test_sink.cc4
-rw-r--r--chromium/ipc/ipc_test_sink.h4
-rw-r--r--chromium/ipc/ipc_tests_apk.isolate17
-rw-r--r--chromium/ipc/mach_port_attachment_mac.cc31
-rw-r--r--chromium/ipc/mach_port_attachment_mac.h22
-rw-r--r--chromium/ipc/mach_port_mac.cc1
-rw-r--r--chromium/ipc/mach_port_mac.h49
-rw-r--r--chromium/ipc/message_filter.cc2
-rw-r--r--chromium/ipc/message_filter_router.cc2
-rw-r--r--chromium/ipc/mojo/BUILD.gn8
-rw-r--r--chromium/ipc/mojo/DEPS2
-rw-r--r--chromium/ipc/mojo/OWNERS4
-rw-r--r--chromium/ipc/mojo/async_handle_waiter.cc1
-rw-r--r--chromium/ipc/mojo/async_handle_waiter.h3
-rw-r--r--chromium/ipc/mojo/async_handle_waiter_unittest.cc5
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo.cc84
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo.h6
-rw-r--r--chromium/ipc/mojo/ipc_channel_mojo_unittest.cc27
-rw-r--r--chromium/ipc/mojo/ipc_message_pipe_reader.cc11
-rw-r--r--chromium/ipc/mojo/ipc_message_pipe_reader.h10
-rw-r--r--chromium/ipc/mojo/ipc_mojo_bootstrap.cc11
-rw-r--r--chromium/ipc/mojo/ipc_mojo_bootstrap.h9
-rw-r--r--chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc11
-rw-r--r--chromium/ipc/mojo/ipc_mojo_handle_attachment.cc8
-rw-r--r--chromium/ipc/mojo/ipc_mojo_handle_attachment.h4
-rw-r--r--chromium/ipc/mojo/ipc_mojo_message_helper.cc4
-rw-r--r--chromium/ipc/mojo/ipc_mojo_message_helper.h2
-rw-r--r--chromium/ipc/mojo/ipc_mojo_param_traits.h2
-rw-r--r--chromium/ipc/mojo/ipc_mojo_perftest.cc5
-rw-r--r--chromium/ipc/mojo/run_all_unittests.cc27
-rw-r--r--chromium/ipc/mojo/scoped_ipc_support.cc38
-rw-r--r--chromium/ipc/placeholder_brokerable_attachment.h1
-rw-r--r--chromium/ipc/run_all_unittests.cc26
-rw-r--r--chromium/ipc/sync_socket_unittest.cc9
-rw-r--r--chromium/ipc/test_util_mac.cc143
-rw-r--r--chromium/ipc/test_util_mac.h61
-rw-r--r--chromium/ipc/unix_domain_socket_util.cc2
-rw-r--r--chromium/ipc/unix_domain_socket_util.h1
-rw-r--r--chromium/ipc/unix_domain_socket_util_unittest.cc2
114 files changed, 4794 insertions, 768 deletions
diff --git a/chromium/ipc/BUILD.gn b/chromium/ipc/BUILD.gn
index 4327bd18057..1dddc13484c 100644
--- a/chromium/ipc/BUILD.gn
+++ b/chromium/ipc/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/nacl/config.gni")
import("//testing/test.gni")
component("ipc") {
@@ -11,14 +12,19 @@ component("ipc") {
"attachment_broker_messages.h",
"attachment_broker_privileged.cc",
"attachment_broker_privileged.h",
+ "attachment_broker_privileged_mac.cc",
+ "attachment_broker_privileged_mac.h",
"attachment_broker_privileged_win.cc",
"attachment_broker_privileged_win.h",
"attachment_broker_unprivileged.cc",
"attachment_broker_unprivileged.h",
+ "attachment_broker_unprivileged_mac.cc",
+ "attachment_broker_unprivileged_mac.h",
"attachment_broker_unprivileged_win.cc",
"attachment_broker_unprivileged_win.h",
"brokerable_attachment.cc",
"brokerable_attachment.h",
+ "brokerable_attachment_mac.cc",
"brokerable_attachment_win.cc",
"handle_attachment_win.cc",
"handle_attachment_win.h",
@@ -61,7 +67,6 @@ component("ipc") {
"ipc_message_start.h",
"ipc_message_utils.cc",
"ipc_message_utils.h",
- "ipc_param_traits.h",
"ipc_platform_file.cc",
"ipc_platform_file.h",
"ipc_platform_file_attachment_posix.cc",
@@ -95,7 +100,7 @@ component("ipc") {
"unix_domain_socket_util.h",
]
- if (is_nacl) {
+ if (is_nacl && !is_nacl_nonsfi) {
sources -= [
"ipc_channel.cc",
"ipc_channel_posix.cc",
@@ -108,12 +113,15 @@ component("ipc") {
]
}
- if (is_win || is_ios) {
+ if (is_win || is_ios || is_nacl_nonsfi) {
sources -= [ "unix_domain_socket_util.cc" ]
}
defines = [ "IPC_IMPLEMENTATION" ]
+ public_deps = [
+ ":param_traits",
+ ]
deps = [
"//base",
@@ -121,98 +129,105 @@ component("ipc") {
"//base/third_party/dynamic_annotations",
]
- if (is_win) {
- # On windows HandleAttachmentWin needs to generate random IDs.
+ if (is_win || is_mac) {
+ # On Windows HandleAttachmentWin needs to generate random IDs.
+ # On Mac MachPortAttachmentMac needs to generate random IDs.
deps += [ "//crypto" ]
}
}
-# TODO(GYP): crbug.com/360936. Get this to build and run on Android.
-if (!is_android) {
- group("ipc_tests_run") {
- testonly = true
- deps = [
- ":ipc_tests",
- ]
- }
+# This is provided as a separate target so other targets can provide param
+# traits implementations without necessarily linking to all of IPC.
+source_set("param_traits") {
+ public = [
+ "ipc_param_traits.h",
+ ]
+}
- test("ipc_tests") {
- sources = [
- "attachment_broker_privileged_win_unittest.cc",
- "attachment_broker_unprivileged_win_unittest.cc",
- "ipc_channel_posix_unittest.cc",
- "ipc_channel_proxy_unittest.cc",
- "ipc_channel_reader_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",
- "ipc_sync_channel_unittest.cc",
- "ipc_sync_message_unittest.cc",
- "ipc_sync_message_unittest.h",
- "ipc_test_message_generator.cc",
- "ipc_test_message_generator.h",
- "ipc_test_messages.h",
- "sync_socket_unittest.cc",
- "unix_domain_socket_util_unittest.cc",
- ]
+group("ipc_tests_run") {
+ testonly = true
+ deps = [
+ ":ipc_tests",
+ ]
+}
- if (is_win || is_ios) {
- sources -= [ "unix_domain_socket_util_unittest.cc" ]
- }
-
- # TODO(brettw) hook up Android testing.
- #if (is_android && gtest_target_type == "shared_library") {
- # deps += "/testing/android/native_test.gyp:native_testNative_code"
- #}
-
- # TODO(brettw) hook up tcmalloc to this target.
- #if (is_posix && !is_mac && !is_android) {
- # if (use_allocator!="none") {
- # deps += "/base/allocator"
- # }
- #}
-
- deps = [
- ":ipc",
- ":test_support",
- "//base",
- "//base:i18n",
- "//base/test:run_all_unittests",
- "//base/test:test_support",
- "//crypto",
- "//testing/gtest",
- ]
+test("ipc_tests") {
+ sources = [
+ "attachment_broker_mac_unittest.cc",
+ "attachment_broker_privileged_mac_unittest.cc",
+ "attachment_broker_privileged_win_unittest.cc",
+ "ipc_channel_posix_unittest.cc",
+ "ipc_channel_proxy_unittest.cc",
+ "ipc_channel_reader_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",
+ "ipc_sync_channel_unittest.cc",
+ "ipc_sync_message_unittest.cc",
+ "ipc_sync_message_unittest.h",
+ "ipc_test_message_generator.cc",
+ "ipc_test_message_generator.h",
+ "ipc_test_messages.h",
+ "sync_socket_unittest.cc",
+ "unix_domain_socket_util_unittest.cc",
+ ]
+
+ if (is_win || is_ios) {
+ sources -= [ "unix_domain_socket_util_unittest.cc" ]
}
- test("ipc_perftests") {
- sources = [
- "ipc_perftests.cc",
- ]
+ # TODO(brettw) hook up Android testing.
+ #if (is_android && gtest_target_type == "shared_library") {
+ # deps += "/testing/android/native_test.gyp:native_testNative_code"
+ #}
- # TODO(brettw) hook up Android testing.
- #if (is_android && gtest_target_type == "shared_library") {
- # deps += "/testing/android/native_test.gyp:native_testNative_code"
- #}
-
- # TODO(brettw) hook up tcmalloc to this target.
- #if (is_posix && !is_mac && !is_android) {
- # if (use_allocator!="none") {
- # deps += "//base/allocator"
- # }
- #}
- deps = [
- ":ipc",
- ":test_support",
- "//base",
- "//base:i18n",
- "//base/test:test_support",
- "//base/test:test_support_perf",
- "//testing/gtest",
- ]
- }
+ # TODO(brettw) hook up tcmalloc to this target.
+ #if (is_posix && !is_mac && !is_android) {
+ # if (use_allocator!="none") {
+ # deps += "/base/allocator"
+ # }
+ #}
+
+ deps = [
+ ":ipc",
+ ":test_support",
+ "//base",
+ "//base:i18n",
+ "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//crypto",
+ "//testing/gtest",
+ ]
+}
+
+test("ipc_perftests") {
+ sources = [
+ "ipc_perftests.cc",
+ ]
+
+ # TODO(brettw) hook up Android testing.
+ #if (is_android && gtest_target_type == "shared_library") {
+ # deps += "/testing/android/native_test.gyp:native_testNative_code"
+ #}
+
+ # TODO(brettw) hook up tcmalloc to this target.
+ #if (is_posix && !is_mac && !is_android) {
+ # if (use_allocator!="none") {
+ # deps += "//base/allocator"
+ # }
+ #}
+ deps = [
+ ":ipc",
+ ":test_support",
+ "//base",
+ "//base:i18n",
+ "//base/test:test_support",
+ "//base/test:test_support_perf",
+ "//testing/gtest",
+ ]
}
source_set("test_support") {
@@ -230,9 +245,13 @@ source_set("test_support") {
"ipc_test_channel_listener.h",
"ipc_test_sink.cc",
"ipc_test_sink.h",
+ "test_util_mac.cc",
+ "test_util_mac.h",
]
- deps = [
+ public_deps = [
":ipc",
+ ]
+ deps = [
"//base",
"//base/test:test_support",
"//testing/gtest",
diff --git a/chromium/ipc/attachment_broker.cc b/chromium/ipc/attachment_broker.cc
index 2fc4fb4fe9c..50e3e2d9ae7 100644
--- a/chromium/ipc/attachment_broker.cc
+++ b/chromium/ipc/attachment_broker.cc
@@ -6,6 +6,10 @@
#include <algorithm>
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/sequenced_task_runner.h"
+
namespace {
IPC::AttachmentBroker* g_attachment_broker = nullptr;
}
@@ -14,8 +18,9 @@ namespace IPC {
// static
void AttachmentBroker::SetGlobal(AttachmentBroker* broker) {
- CHECK(!g_attachment_broker)
- << "An attachment broker already exists with memory address: " << broker;
+ CHECK(!g_attachment_broker || !broker)
+ << "Global attachment broker address: " << broker
+ << ". New attachment broker address: " << broker;
g_attachment_broker = broker;
}
@@ -24,12 +29,13 @@ AttachmentBroker* AttachmentBroker::GetGlobal() {
return g_attachment_broker;
}
-AttachmentBroker::AttachmentBroker() {}
+AttachmentBroker::AttachmentBroker() : last_unique_id_(0) {}
AttachmentBroker::~AttachmentBroker() {}
bool AttachmentBroker::GetAttachmentWithId(
BrokerableAttachment::AttachmentId id,
scoped_refptr<BrokerableAttachment>* out_attachment) {
+ base::AutoLock auto_lock(*get_lock());
for (AttachmentVector::iterator it = attachments_.begin();
it != attachments_.end(); ++it) {
if ((*it)->GetIdentifier() == id) {
@@ -41,31 +47,86 @@ bool AttachmentBroker::GetAttachmentWithId(
return false;
}
-void AttachmentBroker::AddObserver(AttachmentBroker::Observer* observer) {
- auto it = std::find(observers_.begin(), observers_.end(), observer);
- if (it == observers_.end())
- observers_.push_back(observer);
+void AttachmentBroker::AddObserver(
+ AttachmentBroker::Observer* observer,
+ const scoped_refptr<base::SequencedTaskRunner>& runner) {
+ base::AutoLock auto_lock(*get_lock());
+ auto it = std::find_if(observers_.begin(), observers_.end(),
+ [observer](const ObserverInfo& info) {
+ return info.observer == observer;
+ });
+ if (it == observers_.end()) {
+ ObserverInfo info;
+ info.observer = observer;
+ info.runner = runner;
+ info.unique_id = ++last_unique_id_;
+ observers_.push_back(info);
+ }
}
void AttachmentBroker::RemoveObserver(AttachmentBroker::Observer* observer) {
- auto it = std::find(observers_.begin(), observers_.end(), observer);
+ base::AutoLock auto_lock(*get_lock());
+ auto it = std::find_if(observers_.begin(), observers_.end(),
+ [observer](const ObserverInfo& info) {
+ return info.observer == observer;
+ });
if (it != observers_.end())
observers_.erase(it);
}
+void AttachmentBroker::RegisterCommunicationChannel(Endpoint* endpoint) {
+ NOTREACHED();
+}
+
+void AttachmentBroker::DeregisterCommunicationChannel(Endpoint* endpoint) {
+ NOTREACHED();
+}
+
void AttachmentBroker::HandleReceivedAttachment(
const scoped_refptr<BrokerableAttachment>& attachment) {
- attachments_.push_back(attachment);
+ {
+ base::AutoLock auto_lock(*get_lock());
+ attachments_.push_back(attachment);
+ }
NotifyObservers(attachment->GetIdentifier());
}
void AttachmentBroker::NotifyObservers(
const BrokerableAttachment::AttachmentId& id) {
- // Make a copy of observers_ to avoid mutations during iteration.
- std::vector<Observer*> observers = observers_;
- for (Observer* observer : observers) {
- observer->ReceivedBrokerableAttachmentWithId(id);
+ base::AutoLock auto_lock(*get_lock());
+
+ // Dispatch notifications onto the appropriate task runners. This has two
+ // effects:
+ // 1. Ensures that the notification is posted from the right task runner.
+ // 2. Avoids any complications from re-entrant functions, since one of the
+ // observers may be halfway through processing some messages.
+ for (const auto& info : observers_) {
+ info.runner->PostTask(
+ FROM_HERE, base::Bind(&AttachmentBroker::NotifyObserver,
+ base::Unretained(this), info.unique_id, id));
}
}
+void AttachmentBroker::NotifyObserver(
+ int unique_id,
+ const BrokerableAttachment::AttachmentId& id) {
+ Observer* observer = nullptr;
+ {
+ // Check that the same observer is still registered.
+ base::AutoLock auto_lock(*get_lock());
+ auto it = std::find_if(observers_.begin(), observers_.end(),
+ [unique_id](const ObserverInfo& info) {
+ return info.unique_id == unique_id;
+ });
+ if (it == observers_.end())
+ return;
+ observer = it->observer;
+ }
+
+ observer->ReceivedBrokerableAttachmentWithId(id);
+}
+
+AttachmentBroker::ObserverInfo::ObserverInfo() {}
+AttachmentBroker::ObserverInfo::~ObserverInfo() {}
+
} // namespace IPC
diff --git a/chromium/ipc/attachment_broker.h b/chromium/ipc/attachment_broker.h
index 577d76219f9..4cf1ab5de58 100644
--- a/chromium/ipc/attachment_broker.h
+++ b/chromium/ipc/attachment_broker.h
@@ -7,7 +7,10 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/process/process_handle.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_export.h"
#include "ipc/ipc_listener.h"
@@ -16,15 +19,21 @@
// compile any code that calls member functions of AttachmentBroker. This
// prevents symbols only used by AttachmentBroker and its subclasses from
// making it into the binary.
-#if defined(OS_WIN)
+#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
#define USE_ATTACHMENT_BROKER 1
#else
#define USE_ATTACHMENT_BROKER 0
#endif // defined(OS_WIN)
+namespace base {
+class SequencedTaskRunner;
+};
+
namespace IPC {
class AttachmentBroker;
+class Endpoint;
+
// Classes that inherit from this abstract base class are capable of
// communicating with a broker to send and receive attachments to Chrome IPC
// messages.
@@ -63,8 +72,9 @@ class IPC_EXPORT AttachmentBroker : public Listener {
// IPC::Channel to communicate with the broker process. This may be the same
// IPC::Channel that is requesting the brokering of an attachment.
// Returns true on success and false otherwise.
- virtual bool SendAttachmentToProcess(const BrokerableAttachment* attachment,
- base::ProcessId destination_process) = 0;
+ virtual bool SendAttachmentToProcess(
+ const scoped_refptr<BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) = 0;
// Returns whether the attachment was available. If the attachment was
// available, populates the output parameter |attachment|.
@@ -72,9 +82,21 @@ class IPC_EXPORT AttachmentBroker : public Listener {
scoped_refptr<BrokerableAttachment>* attachment);
// Any given observer should only ever add itself once to the observer list.
- void AddObserver(Observer* observer);
+ // Notifications to |observer| will be posted to |runner|.
+ // The |observer| is expected to call RemoveObserver() before being destroyed.
+ void AddObserver(Observer* observer,
+ const scoped_refptr<base::SequencedTaskRunner>& runner);
void RemoveObserver(Observer* observer);
+ // These two methods should only be called by the broker process.
+ //
+ // Each unprivileged process should have one IPC channel on which it
+ // communicates attachment information with the broker process. In the broker
+ // process, these channels must be registered and deregistered with the
+ // Attachment Broker as they are created and destroyed.
+ virtual void RegisterCommunicationChannel(Endpoint* endpoint);
+ virtual void DeregisterCommunicationChannel(Endpoint* endpoint);
+
protected:
using AttachmentVector = std::vector<scoped_refptr<BrokerableAttachment>>;
@@ -85,9 +107,16 @@ class IPC_EXPORT AttachmentBroker : public Listener {
// Informs the observers that a new BrokerableAttachment has been received.
void NotifyObservers(const BrokerableAttachment::AttachmentId& id);
+ // Informs the observer identified by |unique_id| that a new
+ // BrokerableAttachment has been received.
+ void NotifyObserver(int unique_id,
+ const BrokerableAttachment::AttachmentId& id);
+
// This method is exposed for testing only.
AttachmentVector* get_attachments() { return &attachments_; }
+ base::Lock* get_lock() { return &lock_; }
+
private:
#if defined(OS_WIN)
FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerUnprivilegedWinTest,
@@ -103,7 +132,24 @@ class IPC_EXPORT AttachmentBroker : public Listener {
// better performance.
AttachmentVector attachments_;
- std::vector<Observer*> observers_;
+ struct ObserverInfo {
+ ObserverInfo();
+ ~ObserverInfo();
+
+ Observer* observer;
+ int unique_id;
+
+ // Notifications must be dispatched onto |runner|.
+ scoped_refptr<base::SequencedTaskRunner> runner;
+ };
+ std::vector<ObserverInfo> observers_;
+
+ // This member holds the last id given to an ObserverInfo.
+ int last_unique_id_;
+
+ // The AttachmentBroker can be accessed from any thread, so modifications to
+ // internal state must be guarded by a lock.
+ base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(AttachmentBroker);
};
diff --git a/chromium/ipc/attachment_broker_mac_unittest.cc b/chromium/ipc/attachment_broker_mac_unittest.cc
new file mode 100644
index 00000000000..bf994b77db2
--- /dev/null
+++ b/chromium/ipc/attachment_broker_mac_unittest.cc
@@ -0,0 +1,1335 @@
+// 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 "build/build_config.h"
+
+#include <fcntl.h>
+#include <mach/mach_vm.h>
+#include <stddef.h>
+#include <sys/mman.h>
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/time/time.h"
+#include "ipc/attachment_broker_messages.h"
+#include "ipc/attachment_broker_privileged_mac.h"
+#include "ipc/attachment_broker_unprivileged_mac.h"
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_test_base.h"
+#include "ipc/ipc_test_messages.h"
+#include "ipc/test_util_mac.h"
+
+namespace {
+
+const char kDataBuffer1[] = "This is some test data to write to the file.";
+const char kDataBuffer2[] = "The lazy dog and a fox.";
+const char kDataBuffer3[] = "Two green bears but not a potato.";
+const char kDataBuffer4[] = "Red potato is best potato.";
+const std::string g_service_switch_name = "service_name";
+const size_t g_large_message_size = 8 * 1024 * 1024;
+const int g_large_message_count = 1000;
+const size_t g_medium_message_size = 512 * 1024;
+
+// Running the message loop is expected to increase the number of resident
+// pages. The exact amount is non-deterministic, but for a simple test suite
+// like this one, the increase is expected to be less than 1 MB.
+const size_t g_expected_memory_increase = 1024 * 1024;
+
+enum TestResult {
+ RESULT_UNKNOWN,
+ RESULT_SUCCESS,
+ RESULT_FAILURE,
+};
+
+mach_vm_size_t GetResidentSize() {
+ task_basic_info_64 info;
+ mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
+ kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64,
+ reinterpret_cast<task_info_t>(&info), &count);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "Couldn't get resident size.";
+
+ return info.resident_size;
+}
+
+base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment(
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment) {
+ if (attachment->GetType() !=
+ IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) {
+ LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT.";
+ return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
+ }
+
+ if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) {
+ LOG(INFO) << "Brokerable type not MACH_PORT.";
+ return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
+ }
+
+ IPC::internal::MachPortAttachmentMac* received_mach_port_attachment =
+ static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get());
+ base::mac::ScopedMachSendRight send_right(
+ received_mach_port_attachment->get_mach_port());
+ received_mach_port_attachment->reset_mach_port_ownership();
+ return send_right;
+}
+
+// Makes a Mach port backed SharedMemory region and fills it with |contents|.
+scoped_ptr<base::SharedMemory> MakeSharedMemory(const std::string& contents) {
+ base::SharedMemoryHandle shm(contents.size());
+ if (!shm.IsValid()) {
+ LOG(ERROR) << "Failed to make SharedMemoryHandle.";
+ return nullptr;
+ }
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(shm, false));
+ shared_memory->Map(contents.size());
+ memcpy(shared_memory->memory(), contents.c_str(), contents.size());
+ return shared_memory;
+}
+
+// |message| must be deserializable as a TestSharedMemoryHandleMsg1.
+base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1(
+ const IPC::Message& message) {
+ // Expect a message with a brokered attachment.
+ if (!message.HasBrokerableAttachments()) {
+ LOG(ERROR) << "Message missing brokerable attachment.";
+ return base::SharedMemoryHandle();
+ }
+
+ TestSharedMemoryHandleMsg1::Schema::Param p;
+ if (!TestSharedMemoryHandleMsg1::Read(&message, &p)) {
+ LOG(ERROR) << "Failed to deserialize message.";
+ return base::SharedMemoryHandle();
+ }
+
+ return base::get<1>(p);
+}
+
+// |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns
+// whether deserialization was successful. |handle1| and |handle2| are output
+// variables populated on success.
+bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message,
+ base::SharedMemoryHandle* handle1,
+ base::SharedMemoryHandle* handle2) {
+ // Expect a message with a brokered attachment.
+ if (!message.HasBrokerableAttachments()) {
+ LOG(ERROR) << "Message missing brokerable attachment.";
+ return false;
+ }
+
+ TestSharedMemoryHandleMsg2::Schema::Param p;
+ if (!TestSharedMemoryHandleMsg2::Read(&message, &p)) {
+ LOG(ERROR) << "Failed to deserialize message.";
+ return false;
+ }
+
+ *handle1 = base::get<0>(p);
+ *handle2 = base::get<1>(p);
+ return true;
+}
+
+// Returns |nullptr| on error.
+scoped_ptr<base::SharedMemory> MapSharedMemoryHandle(
+ const base::SharedMemoryHandle& shm,
+ bool read_only) {
+ if (!shm.IsValid()) {
+ LOG(ERROR) << "Invalid SharedMemoryHandle";
+ return nullptr;
+ }
+
+ size_t size;
+ if (!shm.GetSize(&size)) {
+ LOG(ERROR) << "Couldn't get size of SharedMemoryHandle";
+ return nullptr;
+ }
+
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(shm, read_only));
+ shared_memory->Map(size);
+ return shared_memory;
+}
+
+// This method maps the SharedMemoryHandle, checks the contents, and then
+// consumes a reference to the underlying Mach port.
+bool CheckContentsOfSharedMemoryHandle(const base::SharedMemoryHandle& shm,
+ const std::string& contents) {
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MapSharedMemoryHandle(shm, false));
+
+ if (memcmp(shared_memory->memory(), contents.c_str(), contents.size()) != 0) {
+ LOG(ERROR) << "Shared Memory contents not equivalent";
+ return false;
+ }
+ return true;
+}
+
+// This method mmaps the FileDescriptor, checks the contents, and then munmaps
+// the FileDescriptor and closes the underlying fd.
+bool CheckContentsOfFileDescriptor(const base::FileDescriptor& file_descriptor,
+ const std::string& contents) {
+ base::ScopedFD fd_closer(file_descriptor.fd);
+ lseek(file_descriptor.fd, 0, SEEK_SET);
+ scoped_ptr<char, base::FreeDeleter> buffer(
+ static_cast<char*>(malloc(contents.size())));
+ if (!base::ReadFromFD(file_descriptor.fd, buffer.get(), contents.size()))
+ return false;
+
+ int result = memcmp(buffer.get(), contents.c_str(), contents.size());
+ return result == 0;
+}
+
+// Open |fp| and populate it with |contents|.
+base::FileDescriptor MakeFileDescriptor(const base::FilePath& fp,
+ const std::string& contents) {
+ int fd = open(fp.value().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
+ base::ScopedFD fd_closer(fd);
+ if (fd <= 0) {
+ LOG(ERROR) << "Error opening file at: " << fp.value();
+ return base::FileDescriptor();
+ }
+
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ LOG(ERROR) << "Error changing offset";
+ return base::FileDescriptor();
+ }
+
+ if (write(fd, contents.c_str(), contents.size()) !=
+ static_cast<ssize_t>(contents.size())) {
+ LOG(ERROR) << "Error writing to file";
+ return base::FileDescriptor();
+ }
+
+ return base::FileDescriptor(fd_closer.release(), true);
+}
+
+// Maps both handles, then checks that their contents matches |contents|. Then
+// checks that changes to one are reflected in the other. Then consumes
+// references to both underlying Mach ports.
+bool CheckContentsOfTwoEquivalentSharedMemoryHandles(
+ const base::SharedMemoryHandle& handle1,
+ const base::SharedMemoryHandle& handle2,
+ const std::string& contents) {
+ scoped_ptr<base::SharedMemory> shared_memory1(
+ MapSharedMemoryHandle(handle1, false));
+ scoped_ptr<base::SharedMemory> shared_memory2(
+ MapSharedMemoryHandle(handle2, false));
+
+ if (memcmp(shared_memory1->memory(), contents.c_str(), contents.size()) !=
+ 0) {
+ LOG(ERROR) << "Incorrect contents in shared_memory1";
+ return false;
+ }
+
+ if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
+ contents.size()) != 0) {
+ LOG(ERROR) << "Incorrect contents in shared_memory2";
+ return false;
+ }
+
+ // Updating shared_memory1 should update shared_memory2.
+ const char known_string[] = "string bean";
+ if (shared_memory1->mapped_size() < strlen(known_string) ||
+ shared_memory2->mapped_size() < strlen(known_string)) {
+ LOG(ERROR) << "Shared memory size is too small";
+ return false;
+ }
+ memcpy(shared_memory1->memory(), known_string, strlen(known_string));
+
+ if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
+ strlen(known_string)) != 0) {
+ LOG(ERROR) << "Incorrect contents in shared_memory2";
+ return false;
+ }
+
+ return true;
+}
+
+// |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns
+// whether the contents of the attached shared memory region matches |contents|.
+// Consumes a reference to the underlying Mach port.
+bool CheckContentsOfMessage1(const IPC::Message& message,
+ const std::string& contents) {
+ base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
+ return CheckContentsOfSharedMemoryHandle(shm, contents);
+}
+
+// Once the test is finished, send a control message to the parent process with
+// the result. The message may require the runloop to be run before its
+// dispatched.
+void SendControlMessage(IPC::Sender* sender, bool success) {
+ IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+ TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE;
+ message->WriteInt(result);
+ sender->Send(message);
+}
+
+// Records the most recently received brokerable attachment's id.
+class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer {
+ public:
+ void ReceivedBrokerableAttachmentWithId(
+ const IPC::BrokerableAttachment::AttachmentId& id) override {
+ id_ = id;
+ }
+ IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; }
+
+ private:
+ IPC::BrokerableAttachment::AttachmentId id_;
+};
+
+// A broker which always sets the current process as the destination process
+// for attachments.
+class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac {
+ public:
+ MockBroker() {}
+ ~MockBroker() override {}
+ bool SendAttachmentToProcess(
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) override {
+ return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
+ attachment, base::Process::Current().Pid());
+ }
+};
+
+// Forwards all messages to |listener_|. Quits the message loop after a
+// message is received, or the channel has an error.
+class ProxyListener : public IPC::Listener {
+ public:
+ ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {}
+ ~ProxyListener() override {}
+
+ // The reason for exiting the message loop.
+ enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR };
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ bool result = false;
+ if (listener_)
+ result = listener_->OnMessageReceived(message);
+ reason_ = MESSAGE_RECEIVED;
+ messages_.push_back(message);
+ base::MessageLoop::current()->QuitNow();
+ return result;
+ }
+
+ void OnChannelError() override {
+ reason_ = CHANNEL_ERROR;
+ base::MessageLoop::current()->QuitNow();
+ }
+
+ void set_listener(IPC::Listener* listener) { listener_ = listener; }
+ Reason get_reason() { return reason_; }
+ IPC::Message get_first_message() {
+ DCHECK(!messages_.empty());
+ return messages_[0];
+ }
+ void pop_first_message() {
+ DCHECK(!messages_.empty());
+ messages_.erase(messages_.begin());
+ }
+ bool has_message() { return !messages_.empty(); }
+
+ private:
+ IPC::Listener* listener_;
+ Reason reason_;
+ std::vector<IPC::Message> messages_;
+};
+
+// Waits for a result to be sent over the channel. Quits the message loop
+// after a message is received, or the channel has an error.
+class ResultListener : public IPC::Listener {
+ public:
+ ResultListener() : result_(RESULT_UNKNOWN) {}
+ ~ResultListener() override {}
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ base::PickleIterator iter(message);
+
+ int result;
+ EXPECT_TRUE(iter.ReadInt(&result));
+ result_ = static_cast<TestResult>(result);
+ return true;
+ }
+
+ TestResult get_result() { return result_; }
+
+ private:
+ TestResult result_;
+};
+
+class MockPortProvider : public base::PortProvider {
+ public:
+ mach_port_t TaskForPid(base::ProcessHandle process) const override {
+ auto it = port_map_.find(process);
+ if (it != port_map_.end())
+ return it->second;
+ return MACH_PORT_NULL;
+ }
+
+ void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
+ port_map_[process] = task_port;
+ NotifyObservers(process);
+ }
+
+ void ClearPortMap() { port_map_.clear(); }
+
+ private:
+ std::map<base::ProcessHandle, mach_port_t> port_map_;
+};
+
+// End-to-end tests for the attachment brokering process on Mac.
+// The parent process acts as an unprivileged process. The child process acts
+// as the privileged process.
+class IPCAttachmentBrokerMacTest : public IPCTestBase {
+ public:
+ IPCAttachmentBrokerMacTest() {}
+ ~IPCAttachmentBrokerMacTest() override {}
+
+ base::CommandLine MakeCmdLine(const std::string& procname) override {
+ base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname);
+ // Pass the service name to the child process.
+ command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
+ return command_line;
+ }
+
+ // Takes ownership of |broker|. Has no effect if called after CommonSetUp().
+ void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) {
+ broker_.reset(broker);
+ }
+
+ // Mach Setup that needs to occur before child processes are forked.
+ void MachPreForkSetUp() {
+ service_name_ = IPC::CreateRandomServiceName();
+ server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release());
+ }
+
+ // Mach Setup that needs to occur after child processes are forked.
+ void MachPostForkSetUp() {
+ client_port_.reset(IPC::ReceiveMachPort(server_port_.get()).release());
+ IPC::SendMachPort(
+ client_port_.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
+ }
+
+ // Setup shared between tests.
+ void CommonSetUp(const char* name) {
+ Init(name);
+ MachPreForkSetUp();
+
+ if (!broker_.get())
+ SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
+
+ broker_->AddObserver(&observer_, task_runner());
+ CreateChannel(&proxy_listener_);
+ broker_->DesignateBrokerCommunicationChannel(channel());
+ ASSERT_TRUE(ConnectChannel());
+ ASSERT_TRUE(StartClient());
+
+ MachPostForkSetUp();
+ active_names_at_start_ = IPC::GetActiveNameCount();
+ get_proxy_listener()->set_listener(&result_listener_);
+ }
+
+ void CheckChildResult() {
+ ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
+ get_proxy_listener()->get_reason());
+ ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS);
+ }
+
+ void FinalCleanUp() {
+ // There should be no leaked names.
+ SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(
+ base::TimeDelta::FromSeconds(10),
+ active_names_at_start_ == IPC::GetActiveNameCount());
+ EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
+
+ // Close the channel so the client's OnChannelError() gets fired.
+ channel()->Close();
+
+ EXPECT_TRUE(WaitForClientShutdown());
+ DestroyChannel();
+ broker_.reset();
+ }
+
+ // Teardown shared between most tests.
+ void CommonTearDown() {
+ CheckChildResult();
+ FinalCleanUp();
+ }
+
+ // Makes a SharedMemory region, fills it with |contents|, sends the handle
+ // over Chrome IPC, and unmaps the region.
+ void SendMessage1(const std::string& contents) {
+ scoped_ptr<base::SharedMemory> shared_memory(MakeSharedMemory(contents));
+ IPC::Message* message =
+ new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
+ sender()->Send(message);
+ }
+
+ ProxyListener* get_proxy_listener() { return &proxy_listener_; }
+ IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); }
+ AttachmentBrokerObserver* get_observer() { return &observer_; }
+ ResultListener* get_result_listener() { return &result_listener_; }
+
+ protected:
+ // The number of active names immediately after set up.
+ mach_msg_type_number_t active_names_at_start_;
+
+ private:
+ ProxyListener proxy_listener_;
+ scoped_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_;
+ AttachmentBrokerObserver observer_;
+
+ // A port on which the main process listens for mach messages from the child
+ // process.
+ base::mac::ScopedMachReceiveRight server_port_;
+
+ // A port on which the child process listens for mach messages from the main
+ // process.
+ base::mac::ScopedMachSendRight client_port_;
+
+ std::string service_name_;
+
+ ResultListener result_listener_;
+};
+
+// These objects are globally accessible, and are expected to outlive all IPC
+// Channels.
+struct ChildProcessGlobals {
+ MockPortProvider port_provider;
+
+ // The broker must be destroyed before the port_provider, so that the broker
+ // gets a chance to unregister itself as an observer. This doesn't matter
+ // outside of tests, since neither port_provider nor broker will ever be
+ // destroyed.
+ scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker;
+ base::mac::ScopedMachSendRight server_task_port;
+
+ // Total resident memory before running the message loop.
+ mach_vm_size_t initial_resident_size;
+
+ // Whether to emit log statements while processing messages.
+ bool message_logging;
+};
+
+using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals);
+
+// Sets up the Mach communication ports with the server. Returns a set of
+// globals that must live at least as long as the test.
+scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
+ base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
+ std::string service_name =
+ cmd_line.GetSwitchValueASCII(g_service_switch_name);
+ base::mac::ScopedMachSendRight server_port(
+ IPC::LookupServer(service_name.c_str()));
+ base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort());
+
+ // Send the port that this process is listening on to the server.
+ IPC::SendMachPort(
+ server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND);
+
+ // Receive the task port of the server process.
+ base::mac::ScopedMachSendRight server_task_port(
+ IPC::ReceiveMachPort(client_port.get()));
+
+ scoped_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals);
+ globals->broker.reset(
+ new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider));
+ globals->port_provider.InsertEntry(getppid(), server_task_port.get());
+ globals->server_task_port.reset(server_task_port.release());
+ globals->message_logging = true;
+ return globals;
+}
+
+int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
+ const char* channel_name) {
+ LOG(INFO) << "Privileged process start.";
+ scoped_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp());
+
+ mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount();
+
+ base::MessageLoopForIO main_message_loop;
+ ProxyListener listener;
+
+ scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
+ IPCTestBase::GetChannelName(channel_name), &listener));
+ globals->broker->RegisterCommunicationChannel(channel.get());
+ CHECK(channel->Connect());
+
+ globals->initial_resident_size = GetResidentSize();
+
+ while (true) {
+ if (globals->message_logging)
+ LOG(INFO) << "Privileged process spinning run loop.";
+ base::MessageLoop::current()->Run();
+ ProxyListener::Reason reason = listener.get_reason();
+ if (reason == ProxyListener::CHANNEL_ERROR)
+ break;
+
+ while (listener.has_message()) {
+ if (globals->message_logging)
+ LOG(INFO) << "Privileged process running callback.";
+ callback(channel.get(), listener.get_first_message(), globals.get());
+ if (globals->message_logging)
+ LOG(INFO) << "Privileged process finishing callback.";
+ listener.pop_first_message();
+ }
+ }
+
+ if (active_names_at_start != IPC::GetActiveNameCount()) {
+ LOG(INFO) << "Memory leak!.";
+ }
+ LOG(INFO) << "Privileged process end.";
+ return 0;
+}
+
+// An unprivileged process makes a shared memory region, and writes a string to
+// it. The SharedMemoryHandle is sent to the privileged process using Chrome
+// IPC. The privileged process checks that it received the same memory region.
+TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("SendSharedMemoryHandle");
+
+ SendMessage1(kDataBuffer1);
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void SendSharedMemoryHandleCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ bool success = CheckContentsOfMessage1(message, kDataBuffer1);
+ SendControlMessage(sender, success);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
+ return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
+ "SendSharedMemoryHandle");
+}
+
+// Similar to SendSharedMemoryHandle, but sends a very long shared memory
+// region.
+TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("SendSharedMemoryHandleLong");
+
+ std::string buffer(1 << 23, 'a');
+ SendMessage1(buffer);
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ std::string buffer(1 << 23, 'a');
+ bool success = CheckContentsOfMessage1(message, buffer);
+ SendControlMessage(sender, success);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) {
+ return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback,
+ "SendSharedMemoryHandleLong");
+}
+
+// Similar to SendSharedMemoryHandle, but sends two different shared memory
+// regions in two messages.
+TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle");
+
+ SendMessage1(kDataBuffer1);
+ SendMessage1(kDataBuffer2);
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void SendTwoMessagesDifferentSharedMemoryHandleCallback(
+ IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ static int count = 0;
+ static bool success = true;
+ ++count;
+ if (count == 1) {
+ success &= CheckContentsOfMessage1(message, kDataBuffer1);
+ } else if (count == 2) {
+ success &= CheckContentsOfMessage1(message, kDataBuffer2);
+ SendControlMessage(sender, success);
+ }
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) {
+ return CommonPrivilegedProcessMain(
+ &SendTwoMessagesDifferentSharedMemoryHandleCallback,
+ "SendTwoMessagesDifferentSharedMemoryHandle");
+}
+
+// Similar to SendSharedMemoryHandle, but sends the same shared memory region in
+// two messages.
+TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("SendTwoMessagesSameSharedMemoryHandle");
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MakeSharedMemory(kDataBuffer1));
+
+ for (int i = 0; i < 2; ++i) {
+ IPC::Message* message =
+ new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
+ sender()->Send(message);
+ }
+ }
+
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void SendTwoMessagesSameSharedMemoryHandleCallback(
+ IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ static int count = 0;
+ static base::SharedMemoryHandle handle1;
+ ++count;
+
+ if (count == 1) {
+ handle1 = GetSharedMemoryHandleFromMsg1(message);
+ } else if (count == 2) {
+ base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message));
+
+ bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
+ handle1, handle2, kDataBuffer1);
+ SendControlMessage(sender, success);
+ }
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) {
+ return CommonPrivilegedProcessMain(
+ &SendTwoMessagesSameSharedMemoryHandleCallback,
+ "SendTwoMessagesSameSharedMemoryHandle");
+}
+
+// Similar to SendSharedMemoryHandle, but sends one message with two different
+// memory regions.
+TEST_F(IPCAttachmentBrokerMacTest,
+ SendOneMessageWithTwoDifferentSharedMemoryHandles) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles");
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory1(
+ MakeSharedMemory(kDataBuffer1));
+ scoped_ptr<base::SharedMemory> shared_memory2(
+ MakeSharedMemory(kDataBuffer2));
+ IPC::Message* message = new TestSharedMemoryHandleMsg2(
+ shared_memory1->handle(), shared_memory2->handle());
+ sender()->Send(message);
+ }
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
+ IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ base::SharedMemoryHandle handle1;
+ base::SharedMemoryHandle handle2;
+ if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
+ LOG(ERROR) << "Failed to deserialize message.";
+ SendControlMessage(sender, false);
+ return;
+ }
+
+ bool success = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
+ CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
+ SendControlMessage(sender, success);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
+ SendOneMessageWithTwoDifferentSharedMemoryHandles) {
+ return CommonPrivilegedProcessMain(
+ &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback,
+ "SendOneMessageWithTwoDifferentSharedMemoryHandles");
+}
+
+// Similar to SendSharedMemoryHandle, but sends one message that contains the
+// same memory region twice.
+TEST_F(IPCAttachmentBrokerMacTest,
+ SendOneMessageWithTwoSameSharedMemoryHandles) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles");
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MakeSharedMemory(kDataBuffer1));
+ IPC::Message* message = new TestSharedMemoryHandleMsg2(
+ shared_memory->handle(), shared_memory->handle());
+ sender()->Send(message);
+ }
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
+ IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ base::SharedMemoryHandle handle1;
+ base::SharedMemoryHandle handle2;
+ if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
+ LOG(ERROR) << "Failed to deserialize message.";
+ SendControlMessage(sender, false);
+ return;
+ }
+
+ bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
+ handle1, handle2, kDataBuffer1);
+ SendControlMessage(sender, success);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
+ SendOneMessageWithTwoSameSharedMemoryHandles) {
+ return CommonPrivilegedProcessMain(
+ &SendOneMessageWithTwoSameSharedMemoryHandlesCallback,
+ "SendOneMessageWithTwoSameSharedMemoryHandles");
+}
+
+// Sends one message with two Posix FDs and two Mach ports.
+TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath fp1, fp2;
+ ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp1));
+ ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp2));
+
+ CommonSetUp("SendPosixFDAndMachPort");
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory1(
+ MakeSharedMemory(kDataBuffer1));
+ scoped_ptr<base::SharedMemory> shared_memory2(
+ MakeSharedMemory(kDataBuffer2));
+
+ base::FileDescriptor file_descriptor1(
+ MakeFileDescriptor(fp1, kDataBuffer3));
+ base::FileDescriptor file_descriptor2(
+ MakeFileDescriptor(fp2, kDataBuffer4));
+
+ IPC::Message* message = new TestSharedMemoryHandleMsg3(
+ file_descriptor1, shared_memory1->handle(), file_descriptor2,
+ shared_memory2->handle());
+ sender()->Send(message);
+ }
+
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ TestSharedMemoryHandleMsg3::Schema::Param p;
+ if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
+ LOG(ERROR) << "Failed to deserialize message.";
+ SendControlMessage(sender, false);
+ return;
+ }
+
+ base::SharedMemoryHandle handle1 = base::get<1>(p);
+ base::SharedMemoryHandle handle2 = base::get<3>(p);
+ bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
+ CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
+ if (!success1)
+ LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
+
+ bool success2 =
+ CheckContentsOfFileDescriptor(base::get<0>(p), kDataBuffer3) &&
+ CheckContentsOfFileDescriptor(base::get<2>(p), kDataBuffer4);
+ if (!success2)
+ LOG(ERROR) << "FileDescriptors have wrong contents.";
+
+ SendControlMessage(sender, success1 && success2);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) {
+ return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback,
+ "SendPosixFDAndMachPort");
+}
+
+// Similar to SendHandle, except the attachment's destination process is this
+// process. This is an unrealistic scenario, but simulates an unprivileged
+// process sending an attachment to another unprivileged process.
+TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ SetBroker(new MockBroker);
+ CommonSetUp("SendSharedMemoryHandleToSelf");
+
+ // Technically, the channel is an endpoint, but we need the proxy listener to
+ // receive the messages so that it can quit the message loop.
+ channel()->SetAttachmentBrokerEndpoint(false);
+ get_proxy_listener()->set_listener(get_broker());
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MakeSharedMemory(kDataBuffer1));
+ mach_port_urefs_t ref_count = IPC::GetMachRefCount(
+ shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
+
+ IPC::Message* message =
+ new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
+ sender()->Send(message);
+
+ // Wait until the child process has sent this process a message.
+ base::MessageLoop::current()->Run();
+
+ // Wait for any asynchronous activity to complete.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ // Get the received attachment.
+ IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id();
+ ASSERT_TRUE(id);
+ scoped_refptr<IPC::BrokerableAttachment> received_attachment;
+ get_broker()->GetAttachmentWithId(*id, &received_attachment);
+ ASSERT_NE(received_attachment.get(), nullptr);
+
+ // Check that it's has the same name, but that the ref count has increased.
+ base::mac::ScopedMachSendRight memory_object(
+ GetMachPortFromBrokeredAttachment(received_attachment));
+ ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject());
+ EXPECT_EQ(ref_count + 1,
+ IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
+ MACH_PORT_RIGHT_SEND));
+ }
+
+ FinalCleanUp();
+}
+
+void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
+ const IPC::Message&,
+ ChildProcessGlobals* globals) {
+ // Do nothing special. The default behavior already runs the
+ // AttachmentBrokerPrivilegedMac.
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) {
+ return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback,
+ "SendSharedMemoryHandleToSelf");
+}
+
+// Similar to SendSharedMemoryHandle, but uses a ChannelProxy instead of a
+// Channel.
+TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ Init("SendSharedMemoryHandleChannelProxy");
+ MachPreForkSetUp();
+
+ SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
+ get_broker()->AddObserver(get_observer(), task_runner());
+
+ scoped_ptr<base::Thread> thread(
+ new base::Thread("ChannelProxyTestServerThread"));
+ base::Thread::Options options;
+ options.message_loop_type = base::MessageLoop::TYPE_IO;
+ thread->StartWithOptions(options);
+
+ CreateChannelProxy(get_proxy_listener(), thread->task_runner().get());
+ get_broker()->DesignateBrokerCommunicationChannel(channel_proxy());
+
+ ASSERT_TRUE(StartClient());
+
+ MachPostForkSetUp();
+ active_names_at_start_ = IPC::GetActiveNameCount();
+ get_proxy_listener()->set_listener(get_result_listener());
+
+ SendMessage1(kDataBuffer1);
+ base::MessageLoop::current()->Run();
+
+ CheckChildResult();
+
+ // There should be no leaked names.
+ EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
+
+ // Close the channel so the client's OnChannelError() gets fired.
+ channel_proxy()->Close();
+
+ EXPECT_TRUE(WaitForClientShutdown());
+ DestroyChannelProxy();
+}
+
+void SendSharedMemoryHandleChannelProxyCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ bool success = CheckContentsOfMessage1(message, kDataBuffer1);
+ SendControlMessage(sender, success);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleChannelProxy) {
+ return CommonPrivilegedProcessMain(
+ &SendSharedMemoryHandleChannelProxyCallback,
+ "SendSharedMemoryHandleChannelProxy");
+}
+
+// Similar to SendSharedMemoryHandle, but first makes a copy of the handle using
+// ShareToProcess().
+TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("ShareToProcess");
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MakeSharedMemory(kDataBuffer1));
+ base::SharedMemoryHandle new_handle;
+ ASSERT_TRUE(shared_memory->ShareToProcess(0, &new_handle));
+ IPC::Message* message =
+ new TestSharedMemoryHandleMsg1(100, new_handle, 200);
+ sender()->Send(message);
+ }
+
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void ShareToProcessCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ bool success = CheckContentsOfMessage1(message, kDataBuffer1);
+ SendControlMessage(sender, success);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareToProcess) {
+ return CommonPrivilegedProcessMain(&ShareToProcessCallback, "ShareToProcess");
+}
+
+// Similar to ShareToProcess, but instead shares the memory object only with
+// read permissions.
+TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("ShareReadOnlyToProcess");
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MakeSharedMemory(kDataBuffer1));
+ base::SharedMemoryHandle new_handle;
+ ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(0, &new_handle));
+ IPC::Message* message =
+ new TestSharedMemoryHandleMsg1(100, new_handle, 200);
+ sender()->Send(message);
+ }
+
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void ShareReadOnlyToProcessCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
+
+ // Try to map the memory as writable.
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MapSharedMemoryHandle(shm, false));
+ ASSERT_EQ(nullptr, shared_memory->memory());
+
+ // Now try as read-only.
+ scoped_ptr<base::SharedMemory> shared_memory2(
+ MapSharedMemoryHandle(shm.Duplicate(), true));
+ int current_prot, max_prot;
+ ASSERT_TRUE(IPC::GetMachProtections(shared_memory2->memory(),
+ shared_memory2->mapped_size(),
+ &current_prot, &max_prot));
+ ASSERT_EQ(VM_PROT_READ, current_prot);
+ ASSERT_EQ(VM_PROT_READ, max_prot);
+
+ bool success =
+ memcmp(shared_memory2->memory(), kDataBuffer1, strlen(kDataBuffer1)) == 0;
+ SendControlMessage(sender, success);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) {
+ return CommonPrivilegedProcessMain(&ShareReadOnlyToProcessCallback,
+ "ShareReadOnlyToProcess");
+}
+
+// Similar to SendSharedMemoryHandleToSelf, but the child process pretends to
+// not have the task port for the parent process.
+TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelfDelayedPort) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ SetBroker(new MockBroker);
+ CommonSetUp("SendSharedMemoryHandleToSelfDelayedPort");
+
+ // Technically, the channel is an endpoint, but we need the proxy listener to
+ // receive the messages so that it can quit the message loop.
+ channel()->SetAttachmentBrokerEndpoint(false);
+ get_proxy_listener()->set_listener(get_broker());
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MakeSharedMemory(kDataBuffer1));
+ mach_port_urefs_t ref_count = IPC::GetMachRefCount(
+ shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
+
+ std::vector<IPC::BrokerableAttachment::AttachmentId> ids;
+ const int kMessagesToTest = 3;
+ for (int i = 0; i < kMessagesToTest; ++i) {
+ base::SharedMemoryHandle h = shared_memory->handle().Duplicate();
+ ids.push_back(
+ IPC::BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce());
+ IPC::internal::MachPortAttachmentMac::WireFormat wire_format(
+ h.GetMemoryObject(), getpid(), ids[i]);
+ sender()->Send(new AttachmentBrokerMsg_DuplicateMachPort(wire_format));
+
+ // Send a dummy message, which will trigger the callback handler in the
+ // child process.
+ sender()->Send(new TestSharedMemoryHandleMsg4(1));
+ }
+
+ int received_message_count = 0;
+ while (received_message_count < kMessagesToTest) {
+ // Wait until the child process has sent this process a message.
+ base::MessageLoop::current()->Run();
+
+ // Wait for any asynchronous activity to complete.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ while (get_proxy_listener()->has_message()) {
+ get_proxy_listener()->pop_first_message();
+ received_message_count++;
+ }
+ }
+
+ for (int i = 0; i < kMessagesToTest; ++i) {
+ IPC::BrokerableAttachment::AttachmentId* id = &ids[i];
+ ASSERT_TRUE(id);
+ scoped_refptr<IPC::BrokerableAttachment> received_attachment;
+ get_broker()->GetAttachmentWithId(*id, &received_attachment);
+ ASSERT_NE(received_attachment.get(), nullptr);
+
+ base::mac::ScopedMachSendRight memory_object(
+ GetMachPortFromBrokeredAttachment(received_attachment));
+ ASSERT_EQ(shared_memory->handle().GetMemoryObject(), memory_object);
+ }
+
+ // Check that the ref count hasn't changed.
+ EXPECT_EQ(ref_count,
+ IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
+ MACH_PORT_RIGHT_SEND));
+ }
+
+ FinalCleanUp();
+}
+
+void SendSharedMemoryHandleToSelfDelayedPortCallback(
+ IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ static int i = 0;
+ static base::ProcessId pid = message.get_sender_pid();
+ static mach_port_t task_port = globals->port_provider.TaskForPid(pid);
+ ++i;
+
+ if (i == 1) {
+ // Pretend to not have the task port for the parent.
+ globals->port_provider.ClearPortMap();
+ } else if (i == 2) {
+ // Intentionally do nothing.
+ } else if (i == 3) {
+ // Setting the task port should trigger callbacks, eventually resulting in
+ // multiple attachment broker messages.
+ globals->port_provider.InsertEntry(pid, task_port);
+ }
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) {
+ return CommonPrivilegedProcessMain(
+ &SendSharedMemoryHandleToSelfDelayedPortCallback,
+ "SendSharedMemoryHandleToSelfDelayedPort");
+}
+
+// Tests the memory usage characteristics of attachment brokering a single large
+// message. This test has the *potential* to be flaky, since it compares
+// resident memory at different points in time, and that measurement is
+// non-deterministic.
+TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("MemoryUsageLargeMessage");
+
+ std::string test_string(g_large_message_size, 'a');
+ SendMessage1(test_string);
+ base::MessageLoop::current()->Run();
+ CommonTearDown();
+}
+
+void MemoryUsageLargeMessageCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ EXPECT_LE(GetResidentSize(),
+ globals->initial_resident_size + g_expected_memory_increase);
+
+ base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MapSharedMemoryHandle(shm, false));
+ EXPECT_LE(GetResidentSize(),
+ globals->initial_resident_size + g_expected_memory_increase);
+
+ char* addr = static_cast<char*>(shared_memory->memory());
+ for (size_t i = 0; i < g_large_message_size; i += 1024) {
+ addr[i] = 'a';
+ }
+ EXPECT_GE(GetResidentSize(),
+ globals->initial_resident_size + g_large_message_size);
+
+ shared_memory.reset();
+#if !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
+ !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \
+ !defined(UNDEFINED_SANITIZER)
+ // Under a sanitizer build, releasing memory does not necessarily reduce the
+ // amount of resident memory.
+ EXPECT_LE(GetResidentSize(),
+ globals->initial_resident_size + g_expected_memory_increase);
+#endif
+
+ SendControlMessage(sender, true);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) {
+ return CommonPrivilegedProcessMain(&MemoryUsageLargeMessageCallback,
+ "MemoryUsageLargeMessage");
+}
+
+// Tests the memory usage characteristics of attachment brokering many small
+// messages. This test has the *potential* to be flaky, since it compares
+// resident memory at different points in time, and that measurement is
+// non-deterministic.
+TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ CommonSetUp("MemoryUsageManyMessages");
+
+ for (int i = 0; i < g_large_message_count; ++i) {
+ std::string message = base::IntToString(i);
+ message += '\0';
+ size_t end = message.size();
+ message.resize(g_medium_message_size);
+ std::fill(message.begin() + end, message.end(), 'a');
+ SendMessage1(message);
+
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+
+ if (get_result_listener()->get_result() == RESULT_UNKNOWN)
+ base::MessageLoop::current()->Run();
+
+ CommonTearDown();
+}
+
+void MemoryUsageManyMessagesCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ static int message_index = 0;
+
+ {
+ // Map the shared memory, and make sure that its pages are counting towards
+ // resident size.
+ base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MapSharedMemoryHandle(shm, false));
+
+ char* addr = static_cast<char*>(shared_memory->memory());
+ std::string message_string(addr);
+ int message_int;
+ ASSERT_TRUE(base::StringToInt(message_string, &message_int));
+ ASSERT_EQ(message_index, message_int);
+ for (size_t i = 0; i < g_medium_message_size; i += 1024) {
+ addr[i] = 'a';
+ }
+ }
+
+ ++message_index;
+
+ if (message_index == 1) {
+ // Disable message logging, since it significantly contributes towards total
+ // memory usage.
+ LOG(INFO) << "Disable privileged process message logging.";
+ globals->message_logging = false;
+ }
+
+ if (message_index == g_large_message_count) {
+ size_t memory_increase_kb =
+ (GetResidentSize() - globals->initial_resident_size) / 1024;
+ LOG(INFO) << "Increase in memory usage in KB: " << memory_increase_kb;
+
+#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
+ defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
+ defined(UNDEFINED_SANITIZER)
+ // Under a sanitizer build, releasing memory does not necessarily reduce the
+ // amount of resident memory.
+ bool success = true;
+#else
+ // The total increase in resident size should be less than 1MB. The exact
+ // amount is not deterministic.
+ bool success = memory_increase_kb < 1024;
+#endif
+
+ SendControlMessage(sender, success);
+ }
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageManyMessages) {
+ return CommonPrivilegedProcessMain(&MemoryUsageManyMessagesCallback,
+ "MemoryUsageManyMessages");
+}
+
+} // namespace
diff --git a/chromium/ipc/attachment_broker_messages.h b/chromium/ipc/attachment_broker_messages.h
index f0e103d007f..d27062ed6a2 100644
--- a/chromium/ipc/attachment_broker_messages.h
+++ b/chromium/ipc/attachment_broker_messages.h
@@ -6,6 +6,7 @@
// Multiply-included message file, hence no include guard.
#include "base/process/process_handle.h"
+#include "build/build_config.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_export.h"
#include "ipc/ipc_message_macros.h"
@@ -14,6 +15,10 @@
#include "ipc/handle_attachment_win.h"
#endif // defined(OS_WIN)
+#if defined(OS_MACOSX)
+#include "ipc/mach_port_attachment_mac.h"
+#endif // defined(OS_MACOSX)
+
// ----------------------------------------------------------------------------
// Serialization of structs.
// ----------------------------------------------------------------------------
@@ -30,6 +35,14 @@ IPC_STRUCT_TRAITS_BEGIN(IPC::internal::HandleAttachmentWin::WireFormat)
IPC_STRUCT_TRAITS_END()
#endif // defined(OS_WIN)
+#if defined(OS_MACOSX)
+IPC_STRUCT_TRAITS_BEGIN(IPC::internal::MachPortAttachmentMac::WireFormat)
+ IPC_STRUCT_TRAITS_MEMBER(mach_port)
+ IPC_STRUCT_TRAITS_MEMBER(destination_process)
+ IPC_STRUCT_TRAITS_MEMBER(attachment_id)
+IPC_STRUCT_TRAITS_END()
+#endif // defined(OS_MACOSX)
+
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT IPC_EXPORT
#define IPC_MESSAGE_START AttachmentBrokerMsgStart
@@ -47,6 +60,16 @@ IPC_MESSAGE_CONTROL1(
IPC::internal::HandleAttachmentWin::WireFormat /* wire_format */)
#endif // defined(OS_WIN)
+#if defined(OS_MACOSX)
+// Sent from a broker process to a non-broker process to indicate that an OSX
+// Mach port has been duplicated. Contains all information necessary for the
+// non-broker process to translate a BrokerAttachment::AttachmentId to a
+// BrokerAttachment.
+IPC_MESSAGE_CONTROL1(
+ AttachmentBrokerMsg_MachPortHasBeenDuplicated,
+ IPC::internal::MachPortAttachmentMac::WireFormat /* wire_format */)
+#endif // defined(OS_MACOSX)
+
// ----------------------------------------------------------------------------
// Messages sent from a non-broker process to a broker process.
// ----------------------------------------------------------------------------
@@ -59,3 +82,12 @@ IPC_MESSAGE_CONTROL1(
AttachmentBrokerMsg_DuplicateWinHandle,
IPC::internal::HandleAttachmentWin::WireFormat /* wire_format */)
#endif // defined(OS_WIN)
+
+#if defined(OS_MACOSX)
+// Sent from a non-broker process to a broker process to request the duplication
+// of a Mach port into a different process (possibly the broker process, or even
+// the original process).
+IPC_MESSAGE_CONTROL1(
+ AttachmentBrokerMsg_DuplicateMachPort,
+ IPC::internal::MachPortAttachmentMac::WireFormat /* wire_format */)
+#endif // defined(OS_MACOSX)
diff --git a/chromium/ipc/attachment_broker_privileged.cc b/chromium/ipc/attachment_broker_privileged.cc
index 0f3ac48c7ed..85c1ac949cd 100644
--- a/chromium/ipc/attachment_broker_privileged.cc
+++ b/chromium/ipc/attachment_broker_privileged.cc
@@ -6,17 +6,114 @@
#include <algorithm>
+#include "base/lazy_instance.h"
#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
#include "ipc/ipc_endpoint.h"
+#if defined(OS_WIN)
+#include "ipc/attachment_broker_privileged_win.h"
+#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach.h>
+
+#include "base/process/port_provider_mac.h"
+#include "ipc/attachment_broker_privileged_mac.h"
+#endif
+
namespace IPC {
-AttachmentBrokerPrivileged::AttachmentBrokerPrivileged() {}
+namespace {
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+
+// A fake port provider that does nothing. Intended for single process unit
+// tests.
+class FakePortProvider : public base::PortProvider {
+ mach_port_t TaskForPid(base::ProcessHandle process) const override {
+ DCHECK_EQ(process, getpid());
+ return mach_task_self();
+ }
+};
+
+base::LazyInstance<FakePortProvider>::Leaky
+ g_fake_port_provider = LAZY_INSTANCE_INITIALIZER;
+
+// Passed as a constructor parameter to AttachmentBrokerPrivilegedMac.
+base::PortProvider* g_port_provider = nullptr;
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
+// On platforms that support attachment brokering, returns a new instance of
+// a platform-specific attachment broker. Otherwise returns |nullptr|.
+// The caller takes ownership of the newly created instance, and is
+// responsible for ensuring that the attachment broker lives longer than
+// every IPC::Channel. The new instance automatically registers itself as the
+// global attachment broker.
+scoped_ptr<AttachmentBrokerPrivileged> CreateBroker() {
+#if defined(OS_WIN)
+ return scoped_ptr<AttachmentBrokerPrivileged>(
+ new IPC::AttachmentBrokerPrivilegedWin);
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ return scoped_ptr<AttachmentBrokerPrivileged>(
+ new IPC::AttachmentBrokerPrivilegedMac(g_port_provider));
+#else
+ return nullptr;
+#endif
+}
+
+// This class is wrapped in a LazyInstance to ensure that its constructor is
+// only called once. The constructor creates an attachment broker and sets it as
+// the global broker.
+class AttachmentBrokerMakeOnce {
+ public:
+ AttachmentBrokerMakeOnce() {
+ attachment_broker_.reset(CreateBroker().release());
+ }
+
+ private:
+ scoped_ptr<IPC::AttachmentBrokerPrivileged> attachment_broker_;
+};
-AttachmentBrokerPrivileged::~AttachmentBrokerPrivileged() {}
+base::LazyInstance<AttachmentBrokerMakeOnce>::Leaky
+ g_attachment_broker_make_once = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+AttachmentBrokerPrivileged::AttachmentBrokerPrivileged() {
+ IPC::AttachmentBroker::SetGlobal(this);
+}
+
+AttachmentBrokerPrivileged::~AttachmentBrokerPrivileged() {
+ IPC::AttachmentBroker::SetGlobal(nullptr);
+}
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+// static
+void AttachmentBrokerPrivileged::CreateBrokerIfNeeded(
+ base::PortProvider* provider) {
+ g_port_provider = provider;
+ g_attachment_broker_make_once.Get();
+}
+#else
+// static
+void AttachmentBrokerPrivileged::CreateBrokerIfNeeded() {
+ g_attachment_broker_make_once.Get();
+}
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
+// static
+void AttachmentBrokerPrivileged::CreateBrokerForSingleProcessTests() {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ CreateBrokerIfNeeded(&g_fake_port_provider.Get());
+#else
+ CreateBrokerIfNeeded();
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+}
void AttachmentBrokerPrivileged::RegisterCommunicationChannel(
Endpoint* endpoint) {
+ base::AutoLock auto_lock(*get_lock());
endpoint->SetAttachmentBrokerEndpoint(true);
auto it = std::find(endpoints_.begin(), endpoints_.end(), endpoint);
DCHECK(endpoints_.end() == it);
@@ -25,12 +122,14 @@ void AttachmentBrokerPrivileged::RegisterCommunicationChannel(
void AttachmentBrokerPrivileged::DeregisterCommunicationChannel(
Endpoint* endpoint) {
+ base::AutoLock auto_lock(*get_lock());
auto it = std::find(endpoints_.begin(), endpoints_.end(), endpoint);
if (it != endpoints_.end())
endpoints_.erase(it);
}
Sender* AttachmentBrokerPrivileged::GetSenderWithProcessId(base::ProcessId id) {
+ get_lock()->AssertAcquired();
auto it = std::find_if(endpoints_.begin(), endpoints_.end(),
[id](Endpoint* c) { return c->GetPeerPID() == id; });
if (it == endpoints_.end())
diff --git a/chromium/ipc/attachment_broker_privileged.h b/chromium/ipc/attachment_broker_privileged.h
index 7b3975acdb2..686bb9d282a 100644
--- a/chromium/ipc/attachment_broker_privileged.h
+++ b/chromium/ipc/attachment_broker_privileged.h
@@ -7,9 +7,18 @@
#include <vector>
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
#include "ipc/attachment_broker.h"
#include "ipc/ipc_export.h"
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+namespace base {
+class PortProvider;
+} // namespace base
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
namespace IPC {
class Endpoint;
@@ -24,16 +33,30 @@ class IPC_EXPORT AttachmentBrokerPrivileged : public IPC::AttachmentBroker {
AttachmentBrokerPrivileged();
~AttachmentBrokerPrivileged() override;
- // Each unprivileged process should have one IPC channel on which it
- // communicates attachment information with the broker process. In the broker
- // process, these channels must be registered and deregistered with the
- // Attachment Broker as they are created and destroyed.
- void RegisterCommunicationChannel(Endpoint* endpoint);
- void DeregisterCommunicationChannel(Endpoint* endpoint);
+ // If there is no global attachment broker, makes a new
+ // AttachmentBrokerPrivileged and sets it as the global attachment broker.
+ // This method is thread safe.
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ static void CreateBrokerIfNeeded(base::PortProvider* provider);
+#else
+ static void CreateBrokerIfNeeded();
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
+ // Similar to CreateBrokerIfNeeded(), but useful for single process unit tests
+ // that don't need real attachment brokering, and don't want to deal with
+ // setting up a fake PortProvider.
+ static void CreateBrokerForSingleProcessTests();
+
+ // AttachmentBroker overrides.
+ void RegisterCommunicationChannel(Endpoint* endpoint) override;
+ void DeregisterCommunicationChannel(Endpoint* endpoint) override;
protected:
// Returns the sender whose peer's process id is |id|.
// Returns nullptr if no sender is found.
+ // The lock returned by get_lock() must already be acquired before calling
+ // this method. The return value is only guaranteed to be valid while the lock
+ // is held.
Sender* GetSenderWithProcessId(base::ProcessId id);
// Errors that can be reported by subclasses.
@@ -48,6 +71,32 @@ class IPC_EXPORT AttachmentBrokerPrivileged : public IPC::AttachmentBroker {
DESTINATION_NOT_FOUND = 1,
// The brokerable attachment did not have a destination process.
NO_DESTINATION = 2,
+ // Error making an intermediate Mach port.
+ ERROR_MAKE_INTERMEDIATE = 3,
+ // Error parsing DuplicateMachPort message.
+ ERROR_PARSE_DUPLICATE_MACH_PORT_MESSAGE = 4,
+ // Couldn't get a task port for the process with a given pid.
+ ERROR_TASK_FOR_PID = 5,
+ // Couldn't make a port with receive rights in the destination process.
+ ERROR_MAKE_RECEIVE_PORT = 6,
+ // Couldn't change the attributes of a Mach port.
+ ERROR_SET_ATTRIBUTES = 7,
+ // Couldn't extract a right from the destination.
+ ERROR_EXTRACT_DEST_RIGHT = 8,
+ // Couldn't send a Mach port in a call to mach_msg().
+ ERROR_SEND_MACH_PORT = 9,
+ // Couldn't decrease the ref count on a Mach port.
+ ERROR_DECREASE_REF = 10,
+ // Couldn't extract a right from the source.
+ ERROR_EXTRACT_SOURCE_RIGHT = 11,
+ // The broker did not have a channel of communication with the source
+ // process.
+ ERROR_SOURCE_NOT_FOUND = 12,
+ // The broker could not open the source or destination process with extra
+ // privileges.
+ ERROR_COULD_NOT_OPEN_SOURCE_OR_DEST = 13,
+ // The broker was asked to transfer a HANDLE with invalid permissions.
+ ERROR_INVALID_PERMISSIONS = 14,
ERROR_MAX
};
diff --git a/chromium/ipc/attachment_broker_privileged_mac.cc b/chromium/ipc/attachment_broker_privileged_mac.cc
new file mode 100644
index 00000000000..c5bed27c68d
--- /dev/null
+++ b/chromium/ipc/attachment_broker_privileged_mac.cc
@@ -0,0 +1,451 @@
+// 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/attachment_broker_privileged_mac.h"
+
+#include <stdint.h>
+
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/port_provider_mac.h"
+#include "base/process/process.h"
+#include "base/synchronization/lock.h"
+#include "ipc/attachment_broker_messages.h"
+#include "ipc/brokerable_attachment.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/mach_port_attachment_mac.h"
+
+namespace {
+
+// Struct for sending a complex Mach message.
+struct MachSendComplexMessage {
+ mach_msg_header_t header;
+ mach_msg_body_t body;
+ mach_msg_port_descriptor_t data;
+};
+
+// Sends a Mach port to |endpoint|. Assumes that |endpoint| is a send once
+// right. Takes ownership of |endpoint|.
+kern_return_t SendMachPort(mach_port_t endpoint,
+ mach_port_t port_to_send,
+ int disposition) {
+ MachSendComplexMessage send_msg;
+ send_msg.header.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0) | MACH_MSGH_BITS_COMPLEX;
+ send_msg.header.msgh_size = sizeof(send_msg);
+ send_msg.header.msgh_remote_port = endpoint;
+ send_msg.header.msgh_local_port = MACH_PORT_NULL;
+ send_msg.header.msgh_reserved = 0;
+ send_msg.header.msgh_id = 0;
+ send_msg.body.msgh_descriptor_count = 1;
+ send_msg.data.name = port_to_send;
+ send_msg.data.disposition = disposition;
+ send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR;
+
+ kern_return_t kr =
+ mach_msg(&send_msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
+ send_msg.header.msgh_size,
+ 0, // receive limit
+ MACH_PORT_NULL, // receive name
+ 0, // timeout
+ MACH_PORT_NULL); // notification port
+
+ if (kr != KERN_SUCCESS)
+ mach_port_deallocate(mach_task_self(), endpoint);
+
+ return kr;
+}
+
+} // namespace
+
+namespace IPC {
+
+AttachmentBrokerPrivilegedMac::AttachmentBrokerPrivilegedMac(
+ base::PortProvider* port_provider)
+ : port_provider_(port_provider) {
+ port_provider_->AddObserver(this);
+}
+
+AttachmentBrokerPrivilegedMac::~AttachmentBrokerPrivilegedMac() {
+ port_provider_->RemoveObserver(this);
+ {
+ base::AutoLock l(precursors_lock_);
+ for (auto it : precursors_)
+ delete it.second;
+ }
+ {
+ base::AutoLock l(extractors_lock_);
+ for (auto it : extractors_)
+ delete it.second;
+ }
+}
+
+bool AttachmentBrokerPrivilegedMac::SendAttachmentToProcess(
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) {
+ switch (attachment->GetBrokerableType()) {
+ case BrokerableAttachment::MACH_PORT: {
+ internal::MachPortAttachmentMac* mach_port_attachment =
+ static_cast<internal::MachPortAttachmentMac*>(attachment.get());
+ MachPortWireFormat wire_format =
+ mach_port_attachment->GetWireFormat(destination_process);
+ AddPrecursor(wire_format.destination_process,
+ base::mac::ScopedMachSendRight(wire_format.mach_port),
+ wire_format.attachment_id);
+ mach_port_attachment->reset_mach_port_ownership();
+ SendPrecursorsForProcess(wire_format.destination_process);
+ return true;
+ }
+ default:
+ NOTREACHED();
+ return false;
+ }
+ return false;
+}
+
+void AttachmentBrokerPrivilegedMac::DeregisterCommunicationChannel(
+ Endpoint* endpoint) {
+ AttachmentBrokerPrivileged::DeregisterCommunicationChannel(endpoint);
+
+ if (!endpoint)
+ return;
+
+ base::ProcessId pid = endpoint->GetPeerPID();
+ if (pid == base::kNullProcessId)
+ return;
+
+ {
+ base::AutoLock l(precursors_lock_);
+ auto it = precursors_.find(pid);
+ if (it != precursors_.end()) {
+ delete it->second;
+ precursors_.erase(pid);
+ }
+ }
+
+ {
+ base::AutoLock l(extractors_lock_);
+ auto it = extractors_.find(pid);
+ if (it != extractors_.end()) {
+ delete it->second;
+ extractors_.erase(pid);
+ }
+ }
+}
+
+bool AttachmentBrokerPrivilegedMac::OnMessageReceived(const Message& msg) {
+ bool handled = true;
+ switch (msg.type()) {
+ IPC_MESSAGE_HANDLER_GENERIC(AttachmentBrokerMsg_DuplicateMachPort,
+ OnDuplicateMachPort(msg))
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ }
+ return handled;
+}
+
+void AttachmentBrokerPrivilegedMac::OnReceivedTaskPort(
+ base::ProcessHandle process) {
+ SendPrecursorsForProcess(process);
+}
+
+AttachmentBrokerPrivilegedMac::AttachmentPrecursor::AttachmentPrecursor(
+ const base::ProcessId& pid,
+ base::mac::ScopedMachSendRight port,
+ const BrokerableAttachment::AttachmentId& id)
+ : pid_(pid), port_(port.release()), id_(id) {}
+
+AttachmentBrokerPrivilegedMac::AttachmentPrecursor::~AttachmentPrecursor() {}
+
+base::mac::ScopedMachSendRight
+AttachmentBrokerPrivilegedMac::AttachmentPrecursor::TakePort() {
+ return base::mac::ScopedMachSendRight(port_.release());
+}
+
+AttachmentBrokerPrivilegedMac::AttachmentExtractor::AttachmentExtractor(
+ const base::ProcessId& source_pid,
+ const base::ProcessId& dest_pid,
+ mach_port_name_t port,
+ const BrokerableAttachment::AttachmentId& id)
+ : source_pid_(source_pid),
+ dest_pid_(dest_pid),
+ port_to_extract_(port),
+ id_(id) {}
+
+AttachmentBrokerPrivilegedMac::AttachmentExtractor::~AttachmentExtractor() {}
+
+void AttachmentBrokerPrivilegedMac::OnDuplicateMachPort(
+ const IPC::Message& message) {
+ DCHECK_NE(0, message.get_sender_pid());
+ AttachmentBrokerMsg_DuplicateMachPort::Param param;
+ if (!AttachmentBrokerMsg_DuplicateMachPort::Read(&message, &param)) {
+ LogError(ERROR_PARSE_DUPLICATE_MACH_PORT_MESSAGE);
+ return;
+ }
+ IPC::internal::MachPortAttachmentMac::WireFormat wire_format =
+ base::get<0>(param);
+
+ if (wire_format.destination_process == base::kNullProcessId) {
+ LogError(NO_DESTINATION);
+ return;
+ }
+
+ AddExtractor(message.get_sender_pid(), wire_format.destination_process,
+ wire_format.mach_port, wire_format.attachment_id);
+ ProcessExtractorsForProcess(message.get_sender_pid());
+}
+
+void AttachmentBrokerPrivilegedMac::RoutePrecursorToSelf(
+ AttachmentPrecursor* precursor) {
+ DCHECK_EQ(base::Process::Current().Pid(), precursor->pid());
+
+ // Intentionally leak the port, since the attachment takes ownership.
+ internal::MachPortAttachmentMac::WireFormat wire_format(
+ precursor->TakePort().release(), precursor->pid(), precursor->id());
+ scoped_refptr<BrokerableAttachment> attachment(
+ new internal::MachPortAttachmentMac(wire_format));
+ HandleReceivedAttachment(attachment);
+}
+
+bool AttachmentBrokerPrivilegedMac::RouteWireFormatToAnother(
+ const MachPortWireFormat& wire_format) {
+ DCHECK_NE(wire_format.destination_process, base::Process::Current().Pid());
+
+ // Another process is the destination.
+ base::ProcessId dest = wire_format.destination_process;
+ base::AutoLock auto_lock(*get_lock());
+ Sender* sender = GetSenderWithProcessId(dest);
+ if (!sender) {
+ // Assuming that this message was not sent from a malicious process, the
+ // channel endpoint that would have received this message will block
+ // forever.
+ LOG(ERROR) << "Failed to deliver brokerable attachment to process with id: "
+ << dest;
+ LogError(DESTINATION_NOT_FOUND);
+ return false;
+ }
+
+ LogError(DESTINATION_FOUND);
+ sender->Send(new AttachmentBrokerMsg_MachPortHasBeenDuplicated(wire_format));
+ return true;
+}
+
+mach_port_name_t AttachmentBrokerPrivilegedMac::CreateIntermediateMachPort(
+ mach_port_t task_port,
+ base::mac::ScopedMachSendRight port_to_insert) {
+ DCHECK_NE(mach_task_self(), task_port);
+ DCHECK_NE(static_cast<mach_port_name_t>(MACH_PORT_NULL), task_port);
+
+ // Make a port with receive rights in the destination task.
+ mach_port_name_t endpoint;
+ kern_return_t kr =
+ mach_port_allocate(task_port, MACH_PORT_RIGHT_RECEIVE, &endpoint);
+ if (kr != KERN_SUCCESS) {
+ LogError(ERROR_MAKE_RECEIVE_PORT);
+ return MACH_PORT_NULL;
+ }
+
+ // Change its message queue limit so that it accepts one message.
+ mach_port_limits limits = {};
+ limits.mpl_qlimit = 1;
+ kr = mach_port_set_attributes(task_port, endpoint, MACH_PORT_LIMITS_INFO,
+ reinterpret_cast<mach_port_info_t>(&limits),
+ MACH_PORT_LIMITS_INFO_COUNT);
+ if (kr != KERN_SUCCESS) {
+ LogError(ERROR_SET_ATTRIBUTES);
+ mach_port_deallocate(task_port, endpoint);
+ return MACH_PORT_NULL;
+ }
+
+ // Get a send right.
+ mach_port_t send_once_right;
+ mach_msg_type_name_t send_right_type;
+ kr =
+ mach_port_extract_right(task_port, endpoint, MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &send_once_right, &send_right_type);
+ if (kr != KERN_SUCCESS) {
+ LogError(ERROR_EXTRACT_DEST_RIGHT);
+ mach_port_deallocate(task_port, endpoint);
+ return MACH_PORT_NULL;
+ }
+ DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND_ONCE),
+ send_right_type);
+
+ // This call takes ownership of |send_once_right|.
+ kr = SendMachPort(
+ send_once_right, port_to_insert.get(), MACH_MSG_TYPE_COPY_SEND);
+ if (kr != KERN_SUCCESS) {
+ LogError(ERROR_SEND_MACH_PORT);
+ mach_port_deallocate(task_port, endpoint);
+ return MACH_PORT_NULL;
+ }
+
+ // Endpoint is intentionally leaked into the destination task. An IPC must be
+ // sent to the destination task so that it can clean up this port.
+ return endpoint;
+}
+
+base::mac::ScopedMachSendRight AttachmentBrokerPrivilegedMac::ExtractNamedRight(
+ mach_port_t task_port,
+ mach_port_name_t named_right) {
+ mach_port_t extracted_right = MACH_PORT_NULL;
+ mach_msg_type_name_t extracted_right_type;
+ kern_return_t kr =
+ mach_port_extract_right(task_port, named_right, MACH_MSG_TYPE_MOVE_SEND,
+ &extracted_right, &extracted_right_type);
+ if (kr != KERN_SUCCESS) {
+ LogError(ERROR_EXTRACT_SOURCE_RIGHT);
+ return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
+ }
+
+ DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND),
+ extracted_right_type);
+
+ return base::mac::ScopedMachSendRight(extracted_right);
+}
+
+AttachmentBrokerPrivilegedMac::MachPortWireFormat
+AttachmentBrokerPrivilegedMac::CopyWireFormat(
+ const MachPortWireFormat& wire_format,
+ uint32_t mach_port) {
+ return MachPortWireFormat(mach_port, wire_format.destination_process,
+ wire_format.attachment_id);
+}
+
+void AttachmentBrokerPrivilegedMac::SendPrecursorsForProcess(
+ base::ProcessId pid) {
+ base::AutoLock l(precursors_lock_);
+ auto it = precursors_.find(pid);
+ if (it == precursors_.end())
+ return;
+
+ // Whether this process is the destination process.
+ bool to_self = pid == base::GetCurrentProcId();
+
+ if (!to_self) {
+ base::AutoLock auto_lock(*get_lock());
+ if (!GetSenderWithProcessId(pid)) {
+ // If there is no sender, then the destination process is no longer
+ // running, or never existed to begin with.
+ LogError(DESTINATION_NOT_FOUND);
+ delete it->second;
+ precursors_.erase(it);
+ return;
+ }
+ }
+
+ mach_port_t task_port = port_provider_->TaskForPid(pid);
+
+ // It's possible that the destination process has not yet provided the
+ // privileged process with its task port.
+ if (!to_self && task_port == MACH_PORT_NULL)
+ return;
+
+ while (!it->second->empty()) {
+ auto precursor_it = it->second->begin();
+ if (to_self) {
+ RoutePrecursorToSelf(*precursor_it);
+ } else {
+ if (!SendPrecursor(*precursor_it, task_port))
+ break;
+ }
+ it->second->erase(precursor_it);
+ }
+
+ delete it->second;
+ precursors_.erase(it);
+}
+
+bool AttachmentBrokerPrivilegedMac::SendPrecursor(
+ AttachmentPrecursor* precursor,
+ mach_port_t task_port) {
+ DCHECK(task_port);
+ internal::MachPortAttachmentMac::WireFormat wire_format(
+ MACH_PORT_NULL, precursor->pid(), precursor->id());
+ base::mac::ScopedMachSendRight port_to_insert = precursor->TakePort();
+ mach_port_name_t intermediate_port = MACH_PORT_NULL;
+ if (port_to_insert.get() != MACH_PORT_NULL) {
+ intermediate_port = CreateIntermediateMachPort(
+ task_port, base::mac::ScopedMachSendRight(port_to_insert.release()));
+ }
+ return RouteWireFormatToAnother(
+ CopyWireFormat(wire_format, intermediate_port));
+}
+
+void AttachmentBrokerPrivilegedMac::AddPrecursor(
+ base::ProcessId pid,
+ base::mac::ScopedMachSendRight port,
+ const BrokerableAttachment::AttachmentId& id) {
+ base::AutoLock l(precursors_lock_);
+ auto it = precursors_.find(pid);
+ if (it == precursors_.end())
+ precursors_[pid] = new ScopedVector<AttachmentPrecursor>;
+
+ precursors_[pid]->push_back(new AttachmentPrecursor(
+ pid, base::mac::ScopedMachSendRight(port.release()), id));
+}
+
+void AttachmentBrokerPrivilegedMac::ProcessExtractorsForProcess(
+ base::ProcessId pid) {
+ base::AutoLock l(extractors_lock_);
+ auto it = extractors_.find(pid);
+ if (it == extractors_.end())
+ return;
+
+ {
+ base::AutoLock auto_lock(*get_lock());
+ if (!GetSenderWithProcessId(pid)) {
+ // If there is no sender, then the source process is no longer running.
+ LogError(ERROR_SOURCE_NOT_FOUND);
+ delete it->second;
+ extractors_.erase(it);
+ return;
+ }
+ }
+
+ mach_port_t task_port = port_provider_->TaskForPid(pid);
+
+ // It's possible that the source process has not yet provided the privileged
+ // process with its task port.
+ if (task_port == MACH_PORT_NULL)
+ return;
+
+ while (!it->second->empty()) {
+ auto extractor_it = it->second->begin();
+ ProcessExtractor(*extractor_it, task_port);
+ it->second->erase(extractor_it);
+ }
+
+ delete it->second;
+ extractors_.erase(it);
+}
+
+void AttachmentBrokerPrivilegedMac::ProcessExtractor(
+ AttachmentExtractor* extractor,
+ mach_port_t task_port) {
+ DCHECK(task_port);
+ base::mac::ScopedMachSendRight send_right =
+ ExtractNamedRight(task_port, extractor->port());
+ AddPrecursor(extractor->dest_pid(),
+ base::mac::ScopedMachSendRight(send_right.release()),
+ extractor->id());
+ SendPrecursorsForProcess(extractor->dest_pid());
+}
+
+void AttachmentBrokerPrivilegedMac::AddExtractor(
+ base::ProcessId source_pid,
+ base::ProcessId dest_pid,
+ mach_port_name_t port,
+ const BrokerableAttachment::AttachmentId& id) {
+ base::AutoLock l(extractors_lock_);
+ DCHECK_NE(base::GetCurrentProcId(), source_pid);
+
+ auto it = extractors_.find(source_pid);
+ if (it == extractors_.end())
+ extractors_[source_pid] = new ScopedVector<AttachmentExtractor>;
+
+ extractors_[source_pid]->push_back(
+ new AttachmentExtractor(source_pid, dest_pid, port, id));
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/attachment_broker_privileged_mac.h b/chromium/ipc/attachment_broker_privileged_mac.h
new file mode 100644
index 00000000000..c13cba01ead
--- /dev/null
+++ b/chromium/ipc/attachment_broker_privileged_mac.h
@@ -0,0 +1,224 @@
+// 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_ATTACHMENT_BROKER_PRIVILEGED_MAC_H_
+#define IPC_ATTACHMENT_BROKER_PRIVILEGED_MAC_H_
+
+#include <mach/mach.h>
+#include <stdint.h>
+
+#include <map>
+
+#include "base/gtest_prod_util.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/process/port_provider_mac.h"
+#include "base/synchronization/lock.h"
+#include "ipc/attachment_broker_privileged.h"
+#include "ipc/ipc_export.h"
+#include "ipc/mach_port_attachment_mac.h"
+
+namespace base {
+class PortProvider;
+} // namespace base
+
+namespace IPC {
+
+// This class is a concrete subclass of AttachmentBrokerPrivileged for the
+// OSX platform.
+//
+// An example of the typical process by which a Mach port gets brokered.
+// Definitions:
+// 1. Let there be three processes P1, U2, U3. P1 is privileged.
+// 2. U2 wants to send a Mach port M2 to U3. If this port is inserted into P1,
+// it will be called M1. If it is inserted into U3, it will be called M3.
+// 3. name() returns a serializable representation of a Mach port that can be
+// passed over chrome IPC.
+// 4. pid() returns the process id of a process.
+//
+// Process:
+// 1. U2 sends a AttachmentBrokerMsg_DuplicateMachPort message to P1. The
+// message contains name(M2), and pid(U3).
+// 2. P1 extracts M2 into its own namespace, making M1.
+// 3. P1 makes a new Mach port R in U3.
+// 4. P1 sends a mach_msg with M1 to R.
+// 5. P1 sends name(R) to U3.
+// 6. U3 retrieves the queued message from R. The kernel automatically
+// translates M1 into the namespace of U3, making M3.
+//
+// The logic of this class is a little bit more complex becauese any or all of
+// P1, U2 and U3 may be the same, and depending on the exact configuration,
+// the creation of R may not be necessary.
+//
+// For the rest of this file, and the corresponding implementation file, R will
+// be called the "intermediate Mach port" and M3 the "final Mach port".
+class IPC_EXPORT AttachmentBrokerPrivilegedMac
+ : public AttachmentBrokerPrivileged,
+ public base::PortProvider::Observer {
+ public:
+ explicit AttachmentBrokerPrivilegedMac(base::PortProvider* port_provider);
+ ~AttachmentBrokerPrivilegedMac() override;
+
+ // IPC::AttachmentBroker overrides.
+ bool SendAttachmentToProcess(
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) override;
+ void DeregisterCommunicationChannel(Endpoint* endpoint) override;
+
+ // IPC::Listener overrides.
+ bool OnMessageReceived(const Message& message) override;
+
+ // base::PortProvider::Observer override.
+ void OnReceivedTaskPort(base::ProcessHandle process) override;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerPrivilegedMacMultiProcessTest,
+ InsertRight);
+ FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerPrivilegedMacMultiProcessTest,
+ InsertSameRightTwice);
+ FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerPrivilegedMacMultiProcessTest,
+ InsertTwoRights);
+ using MachPortWireFormat = internal::MachPortAttachmentMac::WireFormat;
+
+ // Contains all the information necessary to broker an attachment into a
+ // destination process. The only thing that prevents an AttachmentPrecusor
+ // from being immediately processed is if |port_provider_| does not yet have a
+ // task port for |pid|.
+ class IPC_EXPORT AttachmentPrecursor {
+ public:
+ AttachmentPrecursor(const base::ProcessId& pid,
+ base::mac::ScopedMachSendRight port_to_insert,
+ const BrokerableAttachment::AttachmentId& id);
+ ~AttachmentPrecursor();
+
+ // Caller takes ownership of |port_|.
+ base::mac::ScopedMachSendRight TakePort();
+
+ base::ProcessId pid() const { return pid_; }
+ const BrokerableAttachment::AttachmentId id() const { return id_; }
+
+ private:
+ // The pid of the destination process.
+ const base::ProcessId pid_;
+ // The final Mach port, as per definition at the top of this file.
+ base::mac::ScopedMachSendRight port_;
+ // The id of the attachment.
+ const BrokerableAttachment::AttachmentId id_;
+ DISALLOW_COPY_AND_ASSIGN(AttachmentPrecursor);
+ };
+
+ // Contains all the information necessary to extract a send right and create
+ // an AttachmentPrecursor. The only thing that prevents an AttachmentExtractor
+ // from being immediately processed is if |port_provider_| does not yet have a
+ // task port for |source_pid|.
+ class IPC_EXPORT AttachmentExtractor {
+ public:
+ AttachmentExtractor(const base::ProcessId& source_pid,
+ const base::ProcessId& dest_pid,
+ mach_port_name_t port,
+ const BrokerableAttachment::AttachmentId& id);
+ ~AttachmentExtractor();
+
+ base::ProcessId source_pid() const { return source_pid_; }
+ base::ProcessId dest_pid() const { return dest_pid_; }
+ mach_port_name_t port() const { return port_to_extract_; }
+ const BrokerableAttachment::AttachmentId id() const { return id_; }
+
+ private:
+ const base::ProcessId source_pid_;
+ const base::ProcessId dest_pid_;
+ mach_port_name_t port_to_extract_;
+ const BrokerableAttachment::AttachmentId id_;
+ };
+
+ // IPC message handlers.
+ void OnDuplicateMachPort(const Message& message);
+
+ // Duplicates the Mach port referenced from |wire_format| from
+ // |source_process| into |wire_format|'s destination process.
+ MachPortWireFormat DuplicateMachPort(const MachPortWireFormat& wire_format,
+ base::ProcessId source_process);
+
+ // |task_port| is the task port of another process.
+ // |port_to_insert| must be a send right in the current task's name space.
+ // Creates an intermediate Mach port in |pid| and sends |port_to_insert| as a
+ // mach_msg to the intermediate Mach port.
+ // Returns the intermediate port on success, and MACH_PORT_NULL on failure.
+ // This method takes ownership of |port_to_insert|. On success, ownership is
+ // passed to the intermediate Mach port.
+ mach_port_name_t CreateIntermediateMachPort(
+ mach_port_t task_port,
+ base::mac::ScopedMachSendRight port_to_insert);
+
+ // Extracts a copy of the send right to |named_right| from |task_port|.
+ // Returns MACH_PORT_NULL on error.
+ base::mac::ScopedMachSendRight ExtractNamedRight(
+ mach_port_t task_port,
+ mach_port_name_t named_right);
+
+ // Copies an existing |wire_format|, but substitutes in a different mach port.
+ MachPortWireFormat CopyWireFormat(const MachPortWireFormat& wire_format,
+ uint32_t mach_port);
+
+ // |wire_format.destination_process| must be this process.
+ // |wire_format.mach_port| must be the final Mach port.
+ // Consumes a reference to |wire_format.mach_port|, as ownership is implicitly
+ // passed to the consumer of the Chrome IPC message.
+ // Makes an attachment, queues it, and notifies the observers.
+ void RoutePrecursorToSelf(AttachmentPrecursor* precursor);
+
+ // |wire_format.destination_process| must be another process.
+ // |wire_format.mach_port| must be the intermediate Mach port.
+ // Ownership of |wire_format.mach_port| is implicitly passed to the process
+ // that receives the Chrome IPC message.
+ // Returns |false| on irrecoverable error.
+ bool RouteWireFormatToAnother(const MachPortWireFormat& wire_format);
+
+ // Atempts to broker all precursors whose destination is |pid|. Has no effect
+ // if |port_provider_| does not have the task port for |pid|.
+ void SendPrecursorsForProcess(base::ProcessId pid);
+
+ // Brokers a single precursor into the task represented by |task_port|.
+ // Returns |false| on irrecoverable error.
+ bool SendPrecursor(AttachmentPrecursor* precursor, mach_port_t task_port);
+
+ // Add a precursor to |precursors_|. Takes ownership of |port|.
+ void AddPrecursor(base::ProcessId pid,
+ base::mac::ScopedMachSendRight port,
+ const BrokerableAttachment::AttachmentId& id);
+
+ // Atempts to process all extractors whose source is |pid|. Has no effect
+ // if |port_provider_| does not have the task port for |pid|.
+ void ProcessExtractorsForProcess(base::ProcessId pid);
+
+ // Processes a single extractor whose source pid is represented by
+ // |task_port|.
+ void ProcessExtractor(AttachmentExtractor* extractor, mach_port_t task_port);
+
+ // Add an extractor to |extractors_|.
+ void AddExtractor(base::ProcessId source_pid,
+ base::ProcessId dest_pid,
+ mach_port_name_t port,
+ const BrokerableAttachment::AttachmentId& id);
+
+ // The port provider must live at least as long as the AttachmentBroker.
+ base::PortProvider* port_provider_;
+
+ // For each ProcessId, a vector of precursors that are waiting to be
+ // sent.
+ std::map<base::ProcessId, ScopedVector<AttachmentPrecursor>*> precursors_;
+ base::Lock precursors_lock_;
+
+ // For each ProcessId, a vector of extractors that are waiting to be
+ // processed.
+ std::map<base::ProcessId, ScopedVector<AttachmentExtractor>*> extractors_;
+ base::Lock extractors_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerPrivilegedMac);
+};
+
+} // namespace IPC
+
+#endif // IPC_ATTACHMENT_BROKER_PRIVILEGED_MAC_H_
diff --git a/chromium/ipc/attachment_broker_privileged_mac_unittest.cc b/chromium/ipc/attachment_broker_privileged_mac_unittest.cc
new file mode 100644
index 00000000000..15aecb66211
--- /dev/null
+++ b/chromium/ipc/attachment_broker_privileged_mac_unittest.cc
@@ -0,0 +1,435 @@
+// 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/attachment_broker_privileged_mac.h"
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+
+#include "base/command_line.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/port_provider_mac.h"
+#include "base/process/process_handle.h"
+#include "base/sys_info.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "ipc/test_util_mac.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace IPC {
+
+namespace {
+
+static const std::string g_service_switch_name = "service_name";
+
+// Sends a uint32_t to a mach port.
+void SendUInt32(mach_port_t port, uint32_t message) {
+ int message_size = sizeof(uint32_t);
+ int total_size = message_size + sizeof(mach_msg_header_t);
+ void* buffer = malloc(total_size);
+ mach_msg_header_t* header = (mach_msg_header_t*)buffer;
+ header->msgh_remote_port = port;
+ header->msgh_local_port = MACH_PORT_NULL;
+ header->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+ header->msgh_reserved = 0;
+ header->msgh_id = 0;
+ header->msgh_size = total_size;
+ memcpy(static_cast<char*>(buffer) + sizeof(mach_msg_header_t), &message,
+ message_size);
+
+ kern_return_t kr;
+ kr = mach_msg(static_cast<mach_msg_header_t*>(buffer), MACH_SEND_MSG,
+ total_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "SendUInt32";
+ free(buffer);
+}
+
+// Receives a uint32_t from a mach port.
+uint32_t ReceiveUInt32(mach_port_t listening_port) {
+ int message_size = sizeof(uint32_t);
+ int total_size =
+ message_size + sizeof(mach_msg_header_t) + sizeof(mach_msg_trailer_t);
+ int options = MACH_RCV_MSG;
+ void* buffer = malloc(total_size);
+
+ int kr =
+ mach_msg(static_cast<mach_msg_header_t*>(buffer), options, 0, total_size,
+ listening_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "ReceiveUInt32";
+
+ uint32_t response;
+ memcpy(&response, static_cast<char*>(buffer) + sizeof(mach_msg_header_t),
+ message_size);
+
+ free(buffer);
+ return response;
+}
+
+// Sets up the mach communication ports with the server. Returns a port to which
+// the server will send mach objects.
+// |original_name_count| is an output variable that describes the number of
+// active names in this task before the task port is shared with the server.
+base::mac::ScopedMachReceiveRight CommonChildProcessSetUp(
+ mach_msg_type_number_t* original_name_count) {
+ base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
+ std::string service_name =
+ cmd_line.GetSwitchValueASCII(g_service_switch_name);
+ base::mac::ScopedMachSendRight server_port(
+ LookupServer(service_name.c_str()));
+ base::mac::ScopedMachReceiveRight client_port(MakeReceivingPort());
+
+ // |server_port| is a newly allocated right which will be deallocated once
+ // this method returns.
+ *original_name_count = GetActiveNameCount() - 1;
+
+ // Send the port that this process is listening on to the server.
+ SendMachPort(server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND);
+
+ // Send the task port for this process.
+ SendMachPort(server_port.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
+ return client_port;
+}
+
+// Creates a new shared memory region populated with 'a'.
+scoped_ptr<base::SharedMemory> CreateAndPopulateSharedMemoryHandle(
+ size_t size) {
+ base::SharedMemoryHandle shm(size);
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(shm, false));
+ shared_memory->Map(size);
+ memset(shared_memory->memory(), 'a', size);
+ return shared_memory;
+}
+
+// Create a shared memory region from a memory object. The returned object takes
+// ownership of |memory_object|.
+scoped_ptr<base::SharedMemory> MapMemoryObject(mach_port_t memory_object,
+ size_t size) {
+ base::SharedMemoryHandle shm(memory_object, size, base::GetCurrentProcId());
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(shm, false));
+ shared_memory->Map(size);
+ return shared_memory;
+}
+
+class MockPortProvider : public base::PortProvider {
+ public:
+ MockPortProvider() {}
+ ~MockPortProvider() override {}
+ mach_port_t TaskForPid(base::ProcessHandle process) const override {
+ return MACH_PORT_NULL;
+ }
+};
+
+} // namespace
+
+class AttachmentBrokerPrivilegedMacMultiProcessTest
+ : public base::MultiProcessTest {
+ public:
+ AttachmentBrokerPrivilegedMacMultiProcessTest() {}
+
+ base::CommandLine MakeCmdLine(const std::string& procname) override {
+ base::CommandLine command_line = MultiProcessTest::MakeCmdLine(procname);
+ // Pass the service name to the child process.
+ command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
+ return command_line;
+ }
+
+ void SetUpChild(const std::string& name) {
+ // Make a random service name so that this test doesn't conflict with other
+ // similar tests.
+ service_name_ = CreateRandomServiceName();
+ server_port_.reset(BecomeMachServer(service_name_.c_str()).release());
+ child_process_ = SpawnChild(name);
+ client_port_.reset(ReceiveMachPort(server_port_.get()).release());
+ client_task_port_.reset(ReceiveMachPort(server_port_.get()).release());
+ }
+
+ static const int s_memory_size = 99999;
+
+ protected:
+ std::string service_name_;
+
+ // A port on which the main process listens for mach messages from the child
+ // process.
+ base::mac::ScopedMachReceiveRight server_port_;
+
+ // A port on which the child process listens for mach messages from the main
+ // process.
+ base::mac::ScopedMachSendRight client_port_;
+
+ // Child process's task port.
+ base::mac::ScopedMachSendRight client_task_port_;
+
+ // Dummy port provider.
+ MockPortProvider port_provider_;
+
+ base::Process child_process_;
+ DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerPrivilegedMacMultiProcessTest);
+};
+
+// The attachment broker inserts a right for a memory object into the
+// destination task.
+TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertRight) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ SetUpChild("InsertRightClient");
+ mach_msg_type_number_t original_name_count = GetActiveNameCount();
+ IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
+
+ // Create some shared memory.
+ scoped_ptr<base::SharedMemory> shared_memory =
+ CreateAndPopulateSharedMemoryHandle(s_memory_size);
+ ASSERT_TRUE(shared_memory->handle().IsValid());
+
+ // Insert the memory object into the destination task, via an intermediate
+ // port.
+ IncrementMachRefCount(shared_memory->handle().GetMemoryObject(),
+ MACH_PORT_RIGHT_SEND);
+ mach_port_name_t inserted_memory_object = broker.CreateIntermediateMachPort(
+ client_task_port_.get(), base::mac::ScopedMachSendRight(
+ shared_memory->handle().GetMemoryObject()));
+ EXPECT_NE(inserted_memory_object,
+ static_cast<mach_port_name_t>(MACH_PORT_NULL));
+ SendUInt32(client_port_.get(), inserted_memory_object);
+
+ // Check that no names have been leaked.
+ shared_memory.reset();
+ EXPECT_EQ(original_name_count, GetActiveNameCount());
+
+ int rv = -1;
+ ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
+ TestTimeouts::action_timeout(), &rv));
+ EXPECT_EQ(0, rv);
+}
+
+MULTIPROCESS_TEST_MAIN(InsertRightClient) {
+ mach_msg_type_number_t original_name_count = 0;
+ base::mac::ScopedMachReceiveRight client_port(
+ CommonChildProcessSetUp(&original_name_count).release());
+ base::mac::ScopedMachReceiveRight inserted_port(
+ ReceiveUInt32(client_port.get()));
+ base::mac::ScopedMachSendRight memory_object(
+ ReceiveMachPort(inserted_port.get()));
+ inserted_port.reset();
+
+ // The server should have inserted a right into this process.
+ EXPECT_EQ(original_name_count + 1, GetActiveNameCount());
+
+ // Map the memory object and check its contents.
+ scoped_ptr<base::SharedMemory> shared_memory(MapMemoryObject(
+ memory_object.release(),
+ AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
+ const char* start = static_cast<const char*>(shared_memory->memory());
+ for (int i = 0;
+ i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
+ DCHECK_EQ(start[i], 'a');
+ }
+
+ // Check that no names have been leaked.
+ shared_memory.reset();
+ EXPECT_EQ(original_name_count, GetActiveNameCount());
+
+ return 0;
+}
+
+// The attachment broker inserts the right for a memory object into the
+// destination task twice.
+TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertSameRightTwice) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ SetUpChild("InsertSameRightTwiceClient");
+ mach_msg_type_number_t original_name_count = GetActiveNameCount();
+ IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
+
+ // Create some shared memory.
+ scoped_ptr<base::SharedMemory> shared_memory =
+ CreateAndPopulateSharedMemoryHandle(s_memory_size);
+ ASSERT_TRUE(shared_memory->handle().IsValid());
+
+ // Insert the memory object into the destination task, via an intermediate
+ // port, twice.
+ for (int i = 0; i < 2; ++i) {
+ IncrementMachRefCount(shared_memory->handle().GetMemoryObject(),
+ MACH_PORT_RIGHT_SEND);
+ mach_port_name_t inserted_memory_object = broker.CreateIntermediateMachPort(
+ client_task_port_.get(),
+ base::mac::ScopedMachSendRight(
+ shared_memory->handle().GetMemoryObject()));
+ EXPECT_NE(inserted_memory_object,
+ static_cast<mach_port_name_t>(MACH_PORT_NULL));
+ SendUInt32(client_port_.get(), inserted_memory_object);
+ }
+
+ // Check that no names have been leaked.
+ shared_memory.reset();
+ EXPECT_EQ(original_name_count, GetActiveNameCount());
+
+ int rv = -1;
+ ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
+ TestTimeouts::action_timeout(), &rv));
+ EXPECT_EQ(0, rv);
+}
+
+MULTIPROCESS_TEST_MAIN(InsertSameRightTwiceClient) {
+ mach_msg_type_number_t original_name_count = 0;
+ base::mac::ScopedMachReceiveRight client_port(
+ CommonChildProcessSetUp(&original_name_count).release());
+
+ // Receive two memory objects.
+ base::mac::ScopedMachReceiveRight inserted_port(
+ ReceiveUInt32(client_port.get()));
+ base::mac::ScopedMachReceiveRight inserted_port2(
+ ReceiveUInt32(client_port.get()));
+ base::mac::ScopedMachSendRight memory_object(
+ ReceiveMachPort(inserted_port.get()));
+ base::mac::ScopedMachSendRight memory_object2(
+ ReceiveMachPort(inserted_port2.get()));
+ inserted_port.reset();
+ inserted_port2.reset();
+
+ // Both rights are for the same Mach port, so only one new name should appear.
+ EXPECT_EQ(original_name_count + 1, GetActiveNameCount());
+
+ // Map both memory objects and check their contents.
+ scoped_ptr<base::SharedMemory> shared_memory(MapMemoryObject(
+ memory_object.release(),
+ AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
+ char* start = static_cast<char*>(shared_memory->memory());
+ for (int i = 0;
+ i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
+ DCHECK_EQ(start[i], 'a');
+ }
+
+ scoped_ptr<base::SharedMemory> shared_memory2(MapMemoryObject(
+ memory_object2.release(),
+ AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
+ char* start2 = static_cast<char*>(shared_memory2->memory());
+ for (int i = 0;
+ i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
+ DCHECK_EQ(start2[i], 'a');
+ }
+
+ // Check that the contents of both regions are shared.
+ start[0] = 'b';
+ DCHECK_EQ(start2[0], 'b');
+
+ // After releasing one shared memory region, the name count shouldn't change,
+ // since another reference exists.
+ shared_memory.reset();
+ EXPECT_EQ(original_name_count + 1, GetActiveNameCount());
+
+ // After releasing the second shared memory region, the name count should be
+ // as if no names were ever inserted
+ shared_memory2.reset();
+ EXPECT_EQ(original_name_count, GetActiveNameCount());
+
+ return 0;
+}
+
+// The attachment broker inserts the rights for two memory objects into the
+// destination task.
+TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertTwoRights) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ SetUpChild("InsertTwoRightsClient");
+ mach_msg_type_number_t original_name_count = GetActiveNameCount();
+ IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
+
+ for (int i = 0; i < 2; ++i) {
+ // Create some shared memory.
+ scoped_ptr<base::SharedMemory> shared_memory =
+ CreateAndPopulateSharedMemoryHandle(s_memory_size);
+ ASSERT_TRUE(shared_memory->handle().IsValid());
+
+ // Insert the memory object into the destination task, via an intermediate
+ // port.
+ IncrementMachRefCount(shared_memory->handle().GetMemoryObject(),
+ MACH_PORT_RIGHT_SEND);
+ mach_port_name_t inserted_memory_object = broker.CreateIntermediateMachPort(
+ client_task_port_.get(),
+ base::mac::ScopedMachSendRight(
+ shared_memory->handle().GetMemoryObject()));
+ EXPECT_NE(inserted_memory_object,
+ static_cast<mach_port_name_t>(MACH_PORT_NULL));
+ SendUInt32(client_port_.get(), inserted_memory_object);
+ }
+
+ // Check that no names have been leaked.
+ EXPECT_EQ(original_name_count, GetActiveNameCount());
+
+ int rv = -1;
+ ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
+ TestTimeouts::action_timeout(), &rv));
+ EXPECT_EQ(0, rv);
+}
+
+MULTIPROCESS_TEST_MAIN(InsertTwoRightsClient) {
+ mach_msg_type_number_t original_name_count = 0;
+ base::mac::ScopedMachReceiveRight client_port(
+ CommonChildProcessSetUp(&original_name_count).release());
+
+ // Receive two memory objects.
+ base::mac::ScopedMachReceiveRight inserted_port(
+ ReceiveUInt32(client_port.get()));
+ base::mac::ScopedMachReceiveRight inserted_port2(
+ ReceiveUInt32(client_port.get()));
+ base::mac::ScopedMachSendRight memory_object(
+ ReceiveMachPort(inserted_port.get()));
+ base::mac::ScopedMachSendRight memory_object2(
+ ReceiveMachPort(inserted_port2.get()));
+ inserted_port.reset();
+ inserted_port2.reset();
+
+ // There should be two new names to reflect the two new shared memory regions.
+ EXPECT_EQ(original_name_count + 2, GetActiveNameCount());
+
+ // Map both memory objects and check their contents.
+ scoped_ptr<base::SharedMemory> shared_memory(MapMemoryObject(
+ memory_object.release(),
+ AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
+ char* start = static_cast<char*>(shared_memory->memory());
+ for (int i = 0;
+ i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
+ DCHECK_EQ(start[i], 'a');
+ }
+
+ scoped_ptr<base::SharedMemory> shared_memory2(MapMemoryObject(
+ memory_object2.release(),
+ AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
+ char* start2 = static_cast<char*>(shared_memory2->memory());
+ for (int i = 0;
+ i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
+ DCHECK_EQ(start2[i], 'a');
+ }
+
+ // Check that the contents of both regions are not shared.
+ start[0] = 'b';
+ DCHECK_EQ(start2[0], 'a');
+
+ // After releasing one shared memory region, the name count should decrement.
+ shared_memory.reset();
+ EXPECT_EQ(original_name_count + 1, GetActiveNameCount());
+ shared_memory2.reset();
+ EXPECT_EQ(original_name_count, GetActiveNameCount());
+
+ return 0;
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/attachment_broker_privileged_win.cc b/chromium/ipc/attachment_broker_privileged_win.cc
index 6f3bc41649e..c749a09c980 100644
--- a/chromium/ipc/attachment_broker_privileged_win.cc
+++ b/chromium/ipc/attachment_broker_privileged_win.cc
@@ -19,16 +19,17 @@ AttachmentBrokerPrivilegedWin::AttachmentBrokerPrivilegedWin() {}
AttachmentBrokerPrivilegedWin::~AttachmentBrokerPrivilegedWin() {}
bool AttachmentBrokerPrivilegedWin::SendAttachmentToProcess(
- const BrokerableAttachment* attachment,
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment,
base::ProcessId destination_process) {
switch (attachment->GetBrokerableType()) {
case BrokerableAttachment::WIN_HANDLE: {
- const internal::HandleAttachmentWin* handle_attachment =
- static_cast<const internal::HandleAttachmentWin*>(attachment);
+ internal::HandleAttachmentWin* handle_attachment =
+ static_cast<internal::HandleAttachmentWin*>(attachment.get());
HandleWireFormat wire_format =
handle_attachment->GetWireFormat(destination_process);
HandleWireFormat new_wire_format =
DuplicateWinHandle(wire_format, base::Process::Current().Pid());
+ handle_attachment->reset_handle_ownership();
if (new_wire_format.handle == 0)
return false;
RouteDuplicatedHandle(new_wire_format);
@@ -82,6 +83,7 @@ void AttachmentBrokerPrivilegedWin::RouteDuplicatedHandle(
// Another process is the destination.
base::ProcessId dest = wire_format.destination_process;
+ base::AutoLock auto_lock(*get_lock());
Sender* sender = GetSenderWithProcessId(dest);
if (!sender) {
// Assuming that this message was not sent from a malicious process, the
@@ -101,35 +103,45 @@ AttachmentBrokerPrivilegedWin::HandleWireFormat
AttachmentBrokerPrivilegedWin::DuplicateWinHandle(
const HandleWireFormat& wire_format,
base::ProcessId source_pid) {
+ // If the source process is the destination process, then no additional work
+ // is required.
+ if (source_pid == wire_format.destination_process)
+ return wire_format;
+
+ // If the handle is not valid, no additional work is required.
+ if (wire_format.handle == 0)
+ return wire_format;
+
base::Process source_process =
base::Process::OpenWithExtraPrivileges(source_pid);
base::Process dest_process =
base::Process::OpenWithExtraPrivileges(wire_format.destination_process);
- int new_wire_format_handle = 0;
- if (source_process.Handle() && dest_process.Handle()) {
- DWORD desired_access = 0;
- DWORD options = 0;
- switch (wire_format.permissions) {
- case HandleWin::INVALID:
- LOG(ERROR) << "Received invalid permissions for duplication.";
- return CopyWireFormat(wire_format, 0);
- case HandleWin::DUPLICATE:
- options = DUPLICATE_SAME_ACCESS;
- break;
- case HandleWin::FILE_READ_WRITE:
- desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
- break;
- }
-
- HANDLE new_handle;
- HANDLE original_handle = LongToHandle(wire_format.handle);
- DWORD result = ::DuplicateHandle(source_process.Handle(), original_handle,
- dest_process.Handle(), &new_handle,
- desired_access, FALSE, options);
+ if (!source_process.Handle() || !dest_process.Handle()) {
+ LogError(ERROR_COULD_NOT_OPEN_SOURCE_OR_DEST);
+ return wire_format;
+ }
- new_wire_format_handle = (result != 0) ? HandleToLong(new_handle) : 0;
+ DWORD desired_access = 0;
+ DWORD options = DUPLICATE_CLOSE_SOURCE;
+ switch (wire_format.permissions) {
+ case HandleWin::INVALID:
+ LogError(ERROR_INVALID_PERMISSIONS);
+ return CopyWireFormat(wire_format, 0);
+ case HandleWin::DUPLICATE:
+ options |= DUPLICATE_SAME_ACCESS;
+ break;
+ case HandleWin::FILE_READ_WRITE:
+ desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+ break;
}
+ HANDLE new_handle;
+ HANDLE original_handle = LongToHandle(wire_format.handle);
+ DWORD result = ::DuplicateHandle(source_process.Handle(), original_handle,
+ dest_process.Handle(), &new_handle,
+ desired_access, FALSE, options);
+
+ int new_wire_format_handle = (result != 0) ? HandleToLong(new_handle) : 0;
return CopyWireFormat(wire_format, new_wire_format_handle);
}
diff --git a/chromium/ipc/attachment_broker_privileged_win.h b/chromium/ipc/attachment_broker_privileged_win.h
index e986a7b0679..467a97776ee 100644
--- a/chromium/ipc/attachment_broker_privileged_win.h
+++ b/chromium/ipc/attachment_broker_privileged_win.h
@@ -5,6 +5,7 @@
#ifndef IPC_ATTACHMENT_BROKER_PRIVILEGED_WIN_H_
#define IPC_ATTACHMENT_BROKER_PRIVILEGED_WIN_H_
+#include "base/macros.h"
#include "ipc/attachment_broker_privileged.h"
#include "ipc/handle_attachment_win.h"
#include "ipc/ipc_export.h"
@@ -20,8 +21,9 @@ class IPC_EXPORT AttachmentBrokerPrivilegedWin
~AttachmentBrokerPrivilegedWin() override;
// IPC::AttachmentBroker overrides.
- bool SendAttachmentToProcess(const BrokerableAttachment* attachment,
- base::ProcessId destination_process) override;
+ bool SendAttachmentToProcess(
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) override;
// IPC::Listener overrides.
bool OnMessageReceived(const Message& message) override;
@@ -32,7 +34,7 @@ class IPC_EXPORT AttachmentBrokerPrivilegedWin
void OnDuplicateWinHandle(const Message& message);
// Duplicates |wire_Format| from |source_process| into its destination
- // process.
+ // process. Closes the original HANDLE.
HandleWireFormat DuplicateWinHandle(const HandleWireFormat& wire_format,
base::ProcessId source_process);
diff --git a/chromium/ipc/attachment_broker_privileged_win_unittest.cc b/chromium/ipc/attachment_broker_privileged_win_unittest.cc
index 9c4a11952d4..b25214d9d95 100644
--- a/chromium/ipc/attachment_broker_privileged_win_unittest.cc
+++ b/chromium/ipc/attachment_broker_privileged_win_unittest.cc
@@ -10,6 +10,9 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_handle.h"
+#include "base/win/scoped_handle.h"
#include "ipc/attachment_broker_privileged_win.h"
#include "ipc/attachment_broker_unprivileged_win.h"
#include "ipc/handle_attachment_win.h"
@@ -21,7 +24,10 @@
namespace {
+using base::win::ScopedHandle;
+
const char kDataBuffer[] = "This is some test data to write to the file.";
+const size_t kSharedMemorySize = 20000;
// Returns the contents of the file represented by |h| as a std::string.
std::string ReadFromFile(HANDLE h) {
@@ -33,80 +39,107 @@ std::string ReadFromFile(HANDLE h) {
return success ? std::string(buffer, bytes_read) : std::string();
}
-HANDLE GetHandleFromBrokeredAttachment(
+ScopedHandle GetHandleFromBrokeredAttachment(
const scoped_refptr<IPC::BrokerableAttachment>& attachment) {
if (attachment->GetType() !=
IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) {
LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT.";
- return nullptr;
+ return ScopedHandle(nullptr);
}
if (attachment->GetBrokerableType() !=
IPC::BrokerableAttachment::WIN_HANDLE) {
LOG(INFO) << "Brokerable type not WIN_HANDLE.";
- return nullptr;
+ return ScopedHandle(nullptr);
}
IPC::internal::HandleAttachmentWin* received_handle_attachment =
static_cast<IPC::internal::HandleAttachmentWin*>(attachment.get());
- return received_handle_attachment->get_handle();
+ ScopedHandle h(received_handle_attachment->get_handle());
+ received_handle_attachment->reset_handle_ownership();
+ return h;
}
// |message| must be deserializable as a TestHandleWinMsg. Returns the HANDLE,
// or nullptr if deserialization failed.
-HANDLE GetHandleFromTestHandleWinMsg(const IPC::Message& message) {
+ScopedHandle GetHandleFromTestHandleWinMsg(const IPC::Message& message) {
// Expect a message with a brokered attachment.
if (!message.HasBrokerableAttachments()) {
LOG(INFO) << "Message missing brokerable attachment.";
- return nullptr;
+ return ScopedHandle(nullptr);
}
TestHandleWinMsg::Schema::Param p;
bool success = TestHandleWinMsg::Read(&message, &p);
if (!success) {
LOG(INFO) << "Failed to deserialize message.";
- return nullptr;
+ return ScopedHandle(nullptr);
}
IPC::HandleWin handle_win = base::get<1>(p);
- return handle_win.get_handle();
+ return ScopedHandle(handle_win.get_handle());
+}
+
+// Returns a mapped, shared memory region based on the handle in |message|.
+scoped_ptr<base::SharedMemory> GetSharedMemoryFromSharedMemoryHandleMsg1(
+ const IPC::Message& message,
+ size_t size) {
+ // Expect a message with a brokered attachment.
+ if (!message.HasBrokerableAttachments()) {
+ LOG(INFO) << "Message missing brokerable attachment.";
+ return nullptr;
+ }
+
+ TestSharedMemoryHandleMsg1::Schema::Param p;
+ bool success = TestSharedMemoryHandleMsg1::Read(&message, &p);
+ if (!success) {
+ LOG(INFO) << "Failed to deserialize message.";
+ return nullptr;
+ }
+
+ base::SharedMemoryHandle handle = base::get<0>(p);
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(handle, false));
+
+ shared_memory->Map(size);
+ return shared_memory;
}
// |message| must be deserializable as a TestTwoHandleWinMsg. Returns the
// HANDLE, or nullptr if deserialization failed.
-HANDLE GetHandleFromTestTwoHandleWinMsg(const IPC::Message& message,
- int index) {
+bool GetHandleFromTestTwoHandleWinMsg(const IPC::Message& message,
+ HANDLE* h1,
+ HANDLE* h2) {
// Expect a message with a brokered attachment.
if (!message.HasBrokerableAttachments()) {
LOG(INFO) << "Message missing brokerable attachment.";
- return nullptr;
+ return false;
}
TestTwoHandleWinMsg::Schema::Param p;
bool success = TestTwoHandleWinMsg::Read(&message, &p);
if (!success) {
LOG(INFO) << "Failed to deserialize message.";
- return nullptr;
+ return false;
}
- IPC::HandleWin handle_win;
- if (index == 0)
- handle_win = base::get<0>(p);
- else if (index == 1)
- handle_win = base::get<1>(p);
- return handle_win.get_handle();
+ IPC::HandleWin handle_win = base::get<0>(p);
+ *h1 = handle_win.get_handle();
+ handle_win = base::get<1>(p);
+ *h2 = handle_win.get_handle();
+ return true;
}
// |message| must be deserializable as a TestHandleWinMsg. Returns true if the
// attached file HANDLE has contents |kDataBuffer|.
bool CheckContentsOfTestMessage(const IPC::Message& message) {
- HANDLE h = GetHandleFromTestHandleWinMsg(message);
- if (h == nullptr) {
+ ScopedHandle h(GetHandleFromTestHandleWinMsg(message));
+ if (h.Get() == nullptr) {
LOG(INFO) << "Failed to get handle from TestHandleWinMsg.";
return false;
}
- std::string contents = ReadFromFile(h);
+ std::string contents = ReadFromFile(h.Get());
bool success = (contents == std::string(kDataBuffer));
if (!success) {
LOG(INFO) << "Expected contents: " << std::string(kDataBuffer);
@@ -115,6 +148,13 @@ bool CheckContentsOfTestMessage(const IPC::Message& message) {
return success;
}
+// Returns 0 on error.
+DWORD GetCurrentProcessHandleCount() {
+ DWORD handle_count = 0;
+ BOOL success = ::GetProcessHandleCount(::GetCurrentProcess(), &handle_count);
+ return success ? handle_count : 0;
+}
+
enum TestResult {
RESULT_UNKNOWN,
RESULT_SUCCESS,
@@ -220,21 +260,24 @@ class IPCAttachmentBrokerPrivilegedWinTest : public IPCTestBase {
// Takes ownership of |broker|. Has no effect if called after CommonSetUp().
void set_broker(IPC::AttachmentBrokerUnprivilegedWin* broker) {
broker_.reset(broker);
- IPC::AttachmentBroker::SetGlobal(broker);
}
void CommonSetUp() {
if (!broker_.get())
set_broker(new IPC::AttachmentBrokerUnprivilegedWin);
- broker_->AddObserver(&observer_);
- set_attachment_broker(broker_.get());
+ broker_->AddObserver(&observer_, task_runner());
CreateChannel(&proxy_listener_);
broker_->DesignateBrokerCommunicationChannel(channel());
ASSERT_TRUE(ConnectChannel());
ASSERT_TRUE(StartClient());
+
+ handle_count_ = GetCurrentProcessHandleCount();
+ EXPECT_NE(handle_count_, 0u);
}
void CommonTearDown() {
+ EXPECT_EQ(handle_count_, handle_count_);
+
// Close the channel so the client's OnChannelError() gets fired.
channel()->Close();
@@ -270,6 +313,7 @@ class IPCAttachmentBrokerPrivilegedWinTest : public IPCTestBase {
ProxyListener proxy_listener_;
scoped_ptr<IPC::AttachmentBrokerUnprivilegedWin> broker_;
MockObserver observer_;
+ DWORD handle_count_;
};
// A broker which always sets the current process as the destination process
@@ -278,8 +322,9 @@ class MockBroker : public IPC::AttachmentBrokerUnprivilegedWin {
public:
MockBroker() {}
~MockBroker() override {}
- bool SendAttachmentToProcess(const IPC::BrokerableAttachment* attachment,
- base::ProcessId destination_process) override {
+ bool SendAttachmentToProcess(
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) override {
return IPC::AttachmentBrokerUnprivilegedWin::SendAttachmentToProcess(
attachment, base::Process::Current().Pid());
}
@@ -289,7 +334,7 @@ class MockBroker : public IPC::AttachmentBrokerUnprivilegedWin {
// file HANDLE is sent to the privileged process using the attachment broker.
// The privileged process dups the HANDLE into its own HANDLE table. This test
// checks that the file has the same contents in the privileged process.
-TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandle) {
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandle) {
Init("SendHandle");
CommonSetUp();
@@ -311,7 +356,7 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandle) {
// Similar to SendHandle, except the file HANDLE attached to the message has
// neither read nor write permissions.
TEST_F(IPCAttachmentBrokerPrivilegedWinTest,
- DISABLED_SendHandleWithoutPermissions) {
+ SendHandleWithoutPermissions) {
Init("SendHandleWithoutPermissions");
CommonSetUp();
@@ -339,7 +384,7 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest,
// Similar to SendHandle, except the attachment's destination process is this
// process. This is an unrealistic scenario, but simulates an unprivileged
// process sending an attachment to another unprivileged process.
-TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandleToSelf) {
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleToSelf) {
Init("SendHandleToSelf");
set_broker(new MockBroker);
@@ -359,13 +404,12 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandleToSelf) {
get_broker()->GetAttachmentWithId(*id, &received_attachment);
ASSERT_NE(received_attachment.get(), nullptr);
- // Check that it's a new entry in the HANDLE table.
- HANDLE h2 = GetHandleFromBrokeredAttachment(received_attachment);
- EXPECT_NE(h2, h);
- EXPECT_NE(h2, nullptr);
+ // Check that it's a different entry in the HANDLE table.
+ ScopedHandle h2(GetHandleFromBrokeredAttachment(received_attachment));
+ EXPECT_NE(h2.Get(), h);
- // But it still points to the same file.
- std::string contents = ReadFromFile(h);
+ // But still points to the same file.
+ std::string contents = ReadFromFile(h2.Get());
EXPECT_EQ(contents, std::string(kDataBuffer));
CommonTearDown();
@@ -373,7 +417,7 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandleToSelf) {
// Similar to SendHandle, but sends a message with two instances of the same
// handle.
-TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendTwoHandles) {
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendTwoHandles) {
Init("SendTwoHandles");
CommonSetUp();
@@ -381,8 +425,12 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendTwoHandles) {
get_proxy_listener()->set_listener(&result_listener);
HANDLE h = CreateTempFile();
+ HANDLE h2;
+ BOOL result = ::DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(),
+ &h2, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ ASSERT_TRUE(result);
IPC::HandleWin handle_win1(h, IPC::HandleWin::FILE_READ_WRITE);
- IPC::HandleWin handle_win2(h, IPC::HandleWin::FILE_READ_WRITE);
+ IPC::HandleWin handle_win2(h2, IPC::HandleWin::FILE_READ_WRITE);
IPC::Message* message = new TestTwoHandleWinMsg(handle_win1, handle_win2);
sender()->Send(message);
base::MessageLoop::current()->Run();
@@ -396,7 +444,7 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendTwoHandles) {
}
// Similar to SendHandle, but sends the same message twice.
-TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandleTwice) {
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleTwice) {
Init("SendHandleTwice");
CommonSetUp();
@@ -404,8 +452,35 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandleTwice) {
get_proxy_listener()->set_listener(&result_listener);
HANDLE h = CreateTempFile();
+ HANDLE h2;
+ BOOL result = ::DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(),
+ &h2, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ ASSERT_TRUE(result);
SendMessageWithAttachment(h);
- SendMessageWithAttachment(h);
+ SendMessageWithAttachment(h2);
+ base::MessageLoop::current()->Run();
+
+ // Check the result.
+ ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
+ get_proxy_listener()->get_reason());
+ ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS);
+
+ CommonTearDown();
+}
+
+// An unprivileged process makes a shared memory region and sends it to the
+// privileged process.
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendSharedMemoryHandle) {
+ Init("SendSharedMemoryHandle");
+
+ CommonSetUp();
+ ResultListener result_listener;
+ get_proxy_listener()->set_listener(&result_listener);
+
+ scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
+ shared_memory->CreateAndMapAnonymous(kSharedMemorySize);
+ memcpy(shared_memory->memory(), kDataBuffer, strlen(kDataBuffer));
+ sender()->Send(new TestSharedMemoryHandleMsg1(shared_memory->handle()));
base::MessageLoop::current()->Run();
// Check the result.
@@ -427,7 +502,6 @@ int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
// Set up IPC channel.
IPC::AttachmentBrokerPrivilegedWin broker;
- IPC::AttachmentBroker::SetGlobal(&broker);
scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
IPCTestBase::GetChannelName(channel_name), &listener));
broker.RegisterCommunicationChannel(channel.get());
@@ -463,14 +537,14 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandle) {
void SendHandleWithoutPermissionsCallback(IPC::Sender* sender,
const IPC::Message& message) {
- HANDLE h = GetHandleFromTestHandleWinMsg(message);
- if (h != nullptr) {
- SetFilePointer(h, 0, nullptr, FILE_BEGIN);
+ ScopedHandle h(GetHandleFromTestHandleWinMsg(message));
+ if (h.Get() != nullptr) {
+ SetFilePointer(h.Get(), 0, nullptr, FILE_BEGIN);
char buffer[100];
DWORD bytes_read;
BOOL success =
- ::ReadFile(h, buffer, static_cast<DWORD>(strlen(kDataBuffer)),
+ ::ReadFile(h.Get(), buffer, static_cast<DWORD>(strlen(kDataBuffer)),
&bytes_read, nullptr);
if (!success && GetLastError() == ERROR_ACCESS_DENIED) {
SendControlMessage(sender, true);
@@ -498,8 +572,8 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleToSelf) {
void SendTwoHandlesCallback(IPC::Sender* sender, const IPC::Message& message) {
// Check for two handles.
- HANDLE h1 = GetHandleFromTestTwoHandleWinMsg(message, 0);
- HANDLE h2 = GetHandleFromTestTwoHandleWinMsg(message, 1);
+ HANDLE h1, h2;
+ EXPECT_TRUE(GetHandleFromTestTwoHandleWinMsg(message, &h1, &h2));
if (h1 == nullptr || h2 == nullptr) {
SendControlMessage(sender, false);
return;
@@ -561,4 +635,18 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleTwice) {
"SendHandleTwice");
}
+void SendSharedMemoryHandleCallback(IPC::Sender* sender,
+ const IPC::Message& message) {
+ scoped_ptr<base::SharedMemory> shared_memory =
+ GetSharedMemoryFromSharedMemoryHandleMsg1(message, kSharedMemorySize);
+ bool success =
+ memcmp(shared_memory->memory(), kDataBuffer, strlen(kDataBuffer)) == 0;
+ SendControlMessage(sender, success);
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
+ return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
+ "SendSharedMemoryHandle");
+}
+
} // namespace
diff --git a/chromium/ipc/attachment_broker_unprivileged.cc b/chromium/ipc/attachment_broker_unprivileged.cc
index ce4e8ab807a..9286a890057 100644
--- a/chromium/ipc/attachment_broker_unprivileged.cc
+++ b/chromium/ipc/attachment_broker_unprivileged.cc
@@ -5,15 +5,42 @@
#include "ipc/attachment_broker_unprivileged.h"
#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_endpoint.h"
+#if defined(OS_WIN)
+#include "ipc/attachment_broker_unprivileged_win.h"
+#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "ipc/attachment_broker_unprivileged_mac.h"
+#endif
+
namespace IPC {
AttachmentBrokerUnprivileged::AttachmentBrokerUnprivileged()
- : sender_(nullptr) {}
+ : sender_(nullptr) {
+ IPC::AttachmentBroker::SetGlobal(this);
+}
-AttachmentBrokerUnprivileged::~AttachmentBrokerUnprivileged() {}
+AttachmentBrokerUnprivileged::~AttachmentBrokerUnprivileged() {
+ IPC::AttachmentBroker::SetGlobal(nullptr);
+}
+
+// static
+scoped_ptr<AttachmentBrokerUnprivileged>
+AttachmentBrokerUnprivileged::CreateBroker() {
+#if defined(OS_WIN)
+ return scoped_ptr<AttachmentBrokerUnprivileged>(
+ new IPC::AttachmentBrokerUnprivilegedWin);
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ return scoped_ptr<AttachmentBrokerUnprivileged>(
+ new IPC::AttachmentBrokerUnprivilegedMac);
+#else
+ return nullptr;
+#endif
+}
void AttachmentBrokerUnprivileged::DesignateBrokerCommunicationChannel(
Endpoint* endpoint) {
diff --git a/chromium/ipc/attachment_broker_unprivileged.h b/chromium/ipc/attachment_broker_unprivileged.h
index 4f847a62492..b572ff8266a 100644
--- a/chromium/ipc/attachment_broker_unprivileged.h
+++ b/chromium/ipc/attachment_broker_unprivileged.h
@@ -5,6 +5,8 @@
#ifndef IPC_ATTACHMENT_BROKER_UNPRIVILEGED_H_
#define IPC_ATTACHMENT_BROKER_UNPRIVILEGED_H_
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "ipc/attachment_broker.h"
#include "ipc/ipc_export.h"
@@ -20,6 +22,14 @@ class IPC_EXPORT AttachmentBrokerUnprivileged : public IPC::AttachmentBroker {
AttachmentBrokerUnprivileged();
~AttachmentBrokerUnprivileged() override;
+ // On platforms that support attachment brokering, returns a new instance of
+ // a platform-specific attachment broker. Otherwise returns |nullptr|.
+ // The caller takes ownership of the newly created instance, and is
+ // responsible for ensuring that the attachment broker lives longer than
+ // every IPC::Channel. The new instance automatically registers itself as the
+ // global attachment broker.
+ static scoped_ptr<AttachmentBrokerUnprivileged> CreateBroker();
+
// In each unprivileged process, exactly one channel should be used to
// communicate brokerable attachments with the broker process.
void DesignateBrokerCommunicationChannel(Endpoint* endpoint);
@@ -28,7 +38,7 @@ class IPC_EXPORT AttachmentBrokerUnprivileged : public IPC::AttachmentBroker {
IPC::Sender* get_sender() { return sender_; }
// Errors that can be reported by subclasses.
- // These match tools/metrics/histograms.xml.
+ // These match tools/metrics/histograms/histograms.xml.
// This enum is append-only.
enum UMAError {
// The brokerable attachment was successfully processed.
@@ -36,6 +46,8 @@ class IPC_EXPORT AttachmentBrokerUnprivileged : public IPC::AttachmentBroker {
// The brokerable attachment's destination was not the process that received
// the attachment.
WRONG_DESTINATION = 1,
+ // An error occurred while trying to receive a Mach port with mach_msg().
+ ERR_RECEIVE_MACH_MESSAGE = 2,
ERROR_MAX
};
diff --git a/chromium/ipc/attachment_broker_unprivileged_mac.cc b/chromium/ipc/attachment_broker_unprivileged_mac.cc
new file mode 100644
index 00000000000..4e766887d9a
--- /dev/null
+++ b/chromium/ipc/attachment_broker_unprivileged_mac.cc
@@ -0,0 +1,110 @@
+// 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/attachment_broker_unprivileged_mac.h"
+
+#include <mach/mach.h>
+
+#include "base/mac/scoped_mach_port.h"
+#include "base/process/process.h"
+#include "ipc/attachment_broker_messages.h"
+#include "ipc/brokerable_attachment.h"
+#include "ipc/ipc_sender.h"
+#include "ipc/mach_port_attachment_mac.h"
+
+namespace {
+
+// Struct for receiving a complex message.
+struct MachReceiveComplexMessage {
+ mach_msg_header_t header;
+ mach_msg_body_t body;
+ mach_msg_port_descriptor_t data;
+ mach_msg_trailer_t trailer;
+};
+
+// Receives a Mach port from |port_to_listen_on|, which should have exactly one
+// queued message. Returns |MACH_PORT_NULL| on any error.
+base::mac::ScopedMachSendRight ReceiveMachPort(mach_port_t port_to_listen_on) {
+ MachReceiveComplexMessage recv_msg;
+ mach_msg_header_t* recv_hdr = &recv_msg.header;
+ recv_hdr->msgh_local_port = port_to_listen_on;
+ recv_hdr->msgh_size = sizeof(recv_msg);
+
+ kern_return_t kr =
+ mach_msg(recv_hdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
+ recv_hdr->msgh_size, port_to_listen_on, 0, MACH_PORT_NULL);
+ if (kr != KERN_SUCCESS)
+ return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
+ if (recv_msg.header.msgh_id != 0)
+ return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
+ return base::mac::ScopedMachSendRight(recv_msg.data.name);
+}
+
+} // namespace
+
+namespace IPC {
+
+AttachmentBrokerUnprivilegedMac::AttachmentBrokerUnprivilegedMac() {}
+
+AttachmentBrokerUnprivilegedMac::~AttachmentBrokerUnprivilegedMac() {}
+
+bool AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) {
+ switch (attachment->GetBrokerableType()) {
+ case BrokerableAttachment::MACH_PORT: {
+ internal::MachPortAttachmentMac* mach_port_attachment =
+ static_cast<internal::MachPortAttachmentMac*>(attachment.get());
+ internal::MachPortAttachmentMac::WireFormat format =
+ mach_port_attachment->GetWireFormat(destination_process);
+ bool success =
+ get_sender()->Send(new AttachmentBrokerMsg_DuplicateMachPort(format));
+ if (success)
+ mach_port_attachment->reset_mach_port_ownership();
+ return success;
+ }
+ default:
+ NOTREACHED();
+ return false;
+ }
+ return false;
+}
+
+bool AttachmentBrokerUnprivilegedMac::OnMessageReceived(const Message& msg) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(AttachmentBrokerUnprivilegedMac, msg)
+ IPC_MESSAGE_HANDLER(AttachmentBrokerMsg_MachPortHasBeenDuplicated,
+ OnMachPortHasBeenDuplicated)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void AttachmentBrokerUnprivilegedMac::OnMachPortHasBeenDuplicated(
+ const IPC::internal::MachPortAttachmentMac::WireFormat& wire_format) {
+ // The IPC message was intended for a different process. Ignore it.
+ if (wire_format.destination_process != base::Process::Current().Pid()) {
+ // If everything is functioning correctly, this path should not be taken.
+ // However, it's still important to validate all fields of the IPC message.
+ LogError(WRONG_DESTINATION);
+ return;
+ }
+
+ base::mac::ScopedMachReceiveRight message_port(wire_format.mach_port);
+ base::mac::ScopedMachSendRight memory_object(
+ ReceiveMachPort(message_port.get()));
+
+ LogError(memory_object.get() == MACH_PORT_NULL ? ERR_RECEIVE_MACH_MESSAGE
+ : SUCCESS);
+
+ IPC::internal::MachPortAttachmentMac::WireFormat translated_wire_format(
+ memory_object.release(), wire_format.destination_process,
+ wire_format.attachment_id);
+
+ scoped_refptr<BrokerableAttachment> attachment(
+ new IPC::internal::MachPortAttachmentMac(translated_wire_format));
+ HandleReceivedAttachment(attachment);
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/attachment_broker_unprivileged_mac.h b/chromium/ipc/attachment_broker_unprivileged_mac.h
new file mode 100644
index 00000000000..aa058e3ae19
--- /dev/null
+++ b/chromium/ipc/attachment_broker_unprivileged_mac.h
@@ -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.
+
+#ifndef IPC_ATTACHMENT_BROKER_UNPRIVILEGED_MAC_H_
+#define IPC_ATTACHMENT_BROKER_UNPRIVILEGED_MAC_H_
+
+#include "base/macros.h"
+#include "ipc/attachment_broker_unprivileged.h"
+#include "ipc/ipc_export.h"
+#include "ipc/mach_port_attachment_mac.h"
+
+namespace IPC {
+
+class BrokerableAttachment;
+
+// This class is an implementation of AttachmentBroker for the OSX platform
+// for non-privileged processes.
+class IPC_EXPORT AttachmentBrokerUnprivilegedMac
+ : public IPC::AttachmentBrokerUnprivileged {
+ public:
+ AttachmentBrokerUnprivilegedMac();
+ ~AttachmentBrokerUnprivilegedMac() override;
+
+ // IPC::AttachmentBroker overrides.
+ bool SendAttachmentToProcess(
+ const scoped_refptr<IPC::BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) override;
+
+ // IPC::Listener overrides.
+ bool OnMessageReceived(const Message& message) override;
+
+ private:
+ // IPC message handlers.
+ void OnMachPortHasBeenDuplicated(
+ const IPC::internal::MachPortAttachmentMac::WireFormat& wire_format);
+
+ DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerUnprivilegedMac);
+};
+
+} // namespace IPC
+
+#endif // IPC_ATTACHMENT_BROKER_UNPRIVILEGED_MAC_H_
diff --git a/chromium/ipc/attachment_broker_unprivileged_win.cc b/chromium/ipc/attachment_broker_unprivileged_win.cc
index 1151f53ac85..9e01d89fec1 100644
--- a/chromium/ipc/attachment_broker_unprivileged_win.cc
+++ b/chromium/ipc/attachment_broker_unprivileged_win.cc
@@ -17,16 +17,19 @@ AttachmentBrokerUnprivilegedWin::AttachmentBrokerUnprivilegedWin() {}
AttachmentBrokerUnprivilegedWin::~AttachmentBrokerUnprivilegedWin() {}
bool AttachmentBrokerUnprivilegedWin::SendAttachmentToProcess(
- const BrokerableAttachment* attachment,
+ const scoped_refptr<BrokerableAttachment>& attachment,
base::ProcessId destination_process) {
switch (attachment->GetBrokerableType()) {
case BrokerableAttachment::WIN_HANDLE: {
- const internal::HandleAttachmentWin* handle_attachment =
- static_cast<const internal::HandleAttachmentWin*>(attachment);
+ internal::HandleAttachmentWin* handle_attachment =
+ static_cast<internal::HandleAttachmentWin*>(attachment.get());
internal::HandleAttachmentWin::WireFormat format =
handle_attachment->GetWireFormat(destination_process);
- return get_sender()->Send(
+ bool success = get_sender()->Send(
new AttachmentBrokerMsg_DuplicateWinHandle(format));
+ if (success)
+ handle_attachment->reset_handle_ownership();
+ return success;
}
case BrokerableAttachment::MACH_PORT:
case BrokerableAttachment::PLACEHOLDER:
diff --git a/chromium/ipc/attachment_broker_unprivileged_win.h b/chromium/ipc/attachment_broker_unprivileged_win.h
index c3d29092741..2e37dc1ed19 100644
--- a/chromium/ipc/attachment_broker_unprivileged_win.h
+++ b/chromium/ipc/attachment_broker_unprivileged_win.h
@@ -5,6 +5,7 @@
#ifndef IPC_ATTACHMENT_BROKER_UNPRIVILEGED_WIN_H_
#define IPC_ATTACHMENT_BROKER_UNPRIVILEGED_WIN_H_
+#include "base/macros.h"
#include "ipc/attachment_broker_unprivileged.h"
#include "ipc/handle_attachment_win.h"
#include "ipc/ipc_export.h"
@@ -22,8 +23,9 @@ class IPC_EXPORT AttachmentBrokerUnprivilegedWin
~AttachmentBrokerUnprivilegedWin() override;
// IPC::AttachmentBroker overrides.
- bool SendAttachmentToProcess(const BrokerableAttachment* attachment,
- base::ProcessId destination_process) override;
+ bool SendAttachmentToProcess(
+ const scoped_refptr<BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) override;
// IPC::Listener overrides.
bool OnMessageReceived(const Message& message) override;
diff --git a/chromium/ipc/attachment_broker_unprivileged_win_unittest.cc b/chromium/ipc/attachment_broker_unprivileged_win_unittest.cc
deleted file mode 100644
index e67c54a61c7..00000000000
--- a/chromium/ipc/attachment_broker_unprivileged_win_unittest.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "build/build_config.h"
-
-#include <windows.h>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/process/process.h"
-#include "ipc/attachment_broker_messages.h"
-#include "ipc/attachment_broker_unprivileged_win.h"
-#include "ipc/handle_attachment_win.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace IPC {
-
-TEST(AttachmentBrokerUnprivilegedWinTest, ReceiveValidMessage) {
- HANDLE handle = LongToHandle(8);
- base::ProcessId destination = base::Process::Current().Pid();
- scoped_refptr<internal::HandleAttachmentWin> attachment(
- new internal::HandleAttachmentWin(handle, HandleWin::DUPLICATE));
- AttachmentBrokerMsg_WinHandleHasBeenDuplicated msg(
- attachment->GetWireFormat(destination));
- AttachmentBrokerUnprivilegedWin attachment_broker;
- EXPECT_TRUE(attachment_broker.OnMessageReceived(msg));
- EXPECT_EQ(1u, attachment_broker.attachments_.size());
-
- scoped_refptr<BrokerableAttachment> received_attachment =
- attachment_broker.attachments_.front();
- EXPECT_EQ(BrokerableAttachment::WIN_HANDLE,
- received_attachment->GetBrokerableType());
- internal::HandleAttachmentWin* received_handle_attachment =
- static_cast<internal::HandleAttachmentWin*>(received_attachment.get());
- EXPECT_EQ(handle, received_handle_attachment->get_handle());
-}
-
-TEST(AttachmentBrokerUnprivilegedWinTest, ReceiveInvalidMessage) {
- HANDLE handle = LongToHandle(8);
- base::ProcessId destination = base::Process::Current().Pid() + 1;
- scoped_refptr<internal::HandleAttachmentWin> attachment(
- new internal::HandleAttachmentWin(handle, HandleWin::DUPLICATE));
- AttachmentBrokerMsg_WinHandleHasBeenDuplicated msg(
- attachment->GetWireFormat(destination));
- AttachmentBrokerUnprivilegedWin attachment_broker;
- EXPECT_TRUE(attachment_broker.OnMessageReceived(msg));
- EXPECT_EQ(0u, attachment_broker.attachments_.size());
-}
-
-} // namespace IPC
diff --git a/chromium/ipc/brokerable_attachment.cc b/chromium/ipc/brokerable_attachment.cc
index 50bf3338182..96ce5bb6193 100644
--- a/chromium/ipc/brokerable_attachment.cc
+++ b/chromium/ipc/brokerable_attachment.cc
@@ -4,6 +4,9 @@
#include "ipc/brokerable_attachment.h"
+#include <stddef.h>
+
+#include "build/build_config.h"
#include "ipc/attachment_broker.h"
namespace IPC {
diff --git a/chromium/ipc/brokerable_attachment.h b/chromium/ipc/brokerable_attachment.h
index ce3082cd92b..50e7fd21eb9 100644
--- a/chromium/ipc/brokerable_attachment.h
+++ b/chromium/ipc/brokerable_attachment.h
@@ -5,9 +5,13 @@
#ifndef IPC_BROKERABLE_ATTACHMENT_H_
#define IPC_BROKERABLE_ATTACHMENT_H_
+#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
+
#include "base/macros.h"
+#include "build/build_config.h"
#include "ipc/ipc_export.h"
#include "ipc/ipc_message_attachment.h"
@@ -37,21 +41,12 @@ class IPC_EXPORT BrokerableAttachment : public MessageAttachment {
void SerializeToBuffer(char* start_address, size_t size);
bool operator==(const AttachmentId& rhs) const {
- for (size_t i = 0; i < kNonceSize; ++i) {
- if (nonce[i] != rhs.nonce[i])
- return false;
- }
- return true;
+ return std::equal(nonce, nonce + kNonceSize, rhs.nonce);
}
bool operator<(const AttachmentId& rhs) const {
- for (size_t i = 0; i < kNonceSize; ++i) {
- if (nonce[i] < rhs.nonce[i])
- return true;
- if (nonce[i] > rhs.nonce[i])
- return false;
- }
- return false;
+ return std::lexicographical_compare(nonce, nonce + kNonceSize, rhs.nonce,
+ rhs.nonce + kNonceSize);
}
};
diff --git a/chromium/ipc/brokerable_attachment_mac.cc b/chromium/ipc/brokerable_attachment_mac.cc
new file mode 100644
index 00000000000..dbcd86b361e
--- /dev/null
+++ b/chromium/ipc/brokerable_attachment_mac.cc
@@ -0,0 +1,22 @@
+// 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/brokerable_attachment.h"
+
+#include "crypto/random.h"
+
+namespace IPC {
+
+// static
+BrokerableAttachment::AttachmentId
+BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce() {
+ AttachmentId id;
+ // In order to prevent mutually untrusted processes from stealing resources
+ // from one another, the nonce must be secret. This generates a 128-bit,
+ // cryptographicaly-strong random number.
+ crypto::RandBytes(id.nonce, BrokerableAttachment::kNonceSize);
+ return id;
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/handle_attachment_win.cc b/chromium/ipc/handle_attachment_win.cc
index c14adcb801c..39c4ef78c7f 100644
--- a/chromium/ipc/handle_attachment_win.cc
+++ b/chromium/ipc/handle_attachment_win.cc
@@ -11,20 +11,28 @@ namespace internal {
HandleAttachmentWin::HandleAttachmentWin(const HANDLE& handle,
HandleWin::Permissions permissions)
- : handle_(handle), permissions_(permissions) {}
+ : handle_(INVALID_HANDLE_VALUE),
+ permissions_(HandleWin::INVALID),
+ owns_handle_(true) {
+ HANDLE duplicated_handle;
+ BOOL result =
+ ::DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
+ &duplicated_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (result) {
+ handle_ = duplicated_handle;
+ permissions_ = permissions;
+ }
+}
HandleAttachmentWin::HandleAttachmentWin(const WireFormat& wire_format)
: BrokerableAttachment(wire_format.attachment_id),
handle_(LongToHandle(wire_format.handle)),
- permissions_(wire_format.permissions) {}
-
-HandleAttachmentWin::HandleAttachmentWin(
- const BrokerableAttachment::AttachmentId& id)
- : BrokerableAttachment(id),
- handle_(INVALID_HANDLE_VALUE),
- permissions_(HandleWin::INVALID) {}
+ permissions_(wire_format.permissions),
+ owns_handle_(true) {}
HandleAttachmentWin::~HandleAttachmentWin() {
+ if (handle_ != INVALID_HANDLE_VALUE && owns_handle_)
+ ::CloseHandle(handle_);
}
HandleAttachmentWin::BrokerableType HandleAttachmentWin::GetBrokerableType()
diff --git a/chromium/ipc/handle_attachment_win.h b/chromium/ipc/handle_attachment_win.h
index 08880850d4f..5e04bdb3626 100644
--- a/chromium/ipc/handle_attachment_win.h
+++ b/chromium/ipc/handle_attachment_win.h
@@ -41,7 +41,7 @@ class IPC_EXPORT HandleAttachmentWin : public BrokerableAttachment {
// The type is int32_t instead of HANDLE because HANDLE gets typedefed to
// void*, whose size varies between 32 and 64-bit processes. Using a
// int32_t means that 64-bit processes will need to perform both up-casting
- // and down-casting. This is performed using the appropriate Windows apis.
+ // and down-casting. This is performed using the appropriate Windows APIs.
// A value of 0 is equivalent to an invalid handle.
int32_t handle;
@@ -54,9 +54,13 @@ class IPC_EXPORT HandleAttachmentWin : public BrokerableAttachment {
AttachmentId attachment_id;
};
+ // This constructor makes a copy of |handle| and takes ownership of the
+ // result. Should only be called by the sender of a Chrome IPC message.
HandleAttachmentWin(const HANDLE& handle, HandleWin::Permissions permissions);
+
+ // This constructor takes ownership of |wire_format.handle| without making a
+ // copy. Should only be called by the receiver of a Chrome IPC message.
explicit HandleAttachmentWin(const WireFormat& wire_format);
- explicit HandleAttachmentWin(const BrokerableAttachment::AttachmentId& id);
BrokerableType GetBrokerableType() const override;
@@ -65,10 +69,23 @@ class IPC_EXPORT HandleAttachmentWin : public BrokerableAttachment {
HANDLE get_handle() const { return handle_; }
+ // The caller of this method has taken ownership of |handle_|.
+ void reset_handle_ownership() {
+ owns_handle_ = false;
+ handle_ = INVALID_HANDLE_VALUE;
+ }
+
private:
~HandleAttachmentWin() override;
HANDLE handle_;
HandleWin::Permissions permissions_;
+
+ // In the sender process, the attachment owns the HANDLE of a newly created
+ // message. The attachment broker will eventually take ownership, and set
+ // this member to |false|.
+ // In the destination process, the attachment owns the Mach port until a call
+ // to ParamTraits<HandleWin>::Read() takes ownership.
+ bool owns_handle_;
};
} // namespace internal
diff --git a/chromium/ipc/handle_win.cc b/chromium/ipc/handle_win.cc
index 5d259059264..f964c832057 100644
--- a/chromium/ipc/handle_win.cc
+++ b/chromium/ipc/handle_win.cc
@@ -4,10 +4,14 @@
#include "ipc/handle_win.h"
+#include <utility>
+
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
#include "ipc/handle_attachment_win.h"
+#include "ipc/ipc_message.h"
namespace IPC {
@@ -21,7 +25,7 @@ void ParamTraits<HandleWin>::Write(Message* m, const param_type& p) {
scoped_refptr<IPC::internal::HandleAttachmentWin> attachment(
new IPC::internal::HandleAttachmentWin(p.get_handle(),
p.get_permissions()));
- if (!m->WriteAttachment(attachment.Pass()))
+ if (!m->WriteAttachment(std::move(attachment)))
NOTREACHED();
}
@@ -43,12 +47,13 @@ bool ParamTraits<HandleWin>::Read(const Message* m,
IPC::internal::HandleAttachmentWin* handle_attachment =
static_cast<IPC::internal::HandleAttachmentWin*>(brokerable_attachment);
r->set_handle(handle_attachment->get_handle());
+ handle_attachment->reset_handle_ownership();
return true;
}
// static
void ParamTraits<HandleWin>::Log(const param_type& p, std::string* l) {
- l->append(base::StringPrintf("0x%X", p.get_handle()));
+ l->append(base::StringPrintf("0x%p", p.get_handle()));
l->append(base::IntToString(p.get_permissions()));
}
diff --git a/chromium/ipc/handle_win.h b/chromium/ipc/handle_win.h
index a8f6978bb2d..38cddae10b1 100644
--- a/chromium/ipc/handle_win.h
+++ b/chromium/ipc/handle_win.h
@@ -7,14 +7,26 @@
#include <windows.h>
+#include <string>
+
#include "ipc/ipc_export.h"
-#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+
+namespace base {
+class PickleIterator;
+} // namespace base
namespace IPC {
+class Message;
+
// HandleWin is a wrapper around a Windows HANDLE that can be transported
// across Chrome IPC channels that support attachment brokering. The HANDLE will
// be duplicated into the destination process.
+//
+// The ownership semantics for the underlying |handle_| are complex. See
+// ipc/mach_port_mac.h (the OSX analog of this class) for an extensive
+// discussion.
class IPC_EXPORT HandleWin {
public:
enum Permissions {
diff --git a/chromium/ipc/ipc.gyp b/chromium/ipc/ipc.gyp
index 7924ec626ac..05b99895112 100644
--- a/chromium/ipc/ipc.gyp
+++ b/chromium/ipc/ipc.gyp
@@ -29,7 +29,7 @@
],
},
'conditions': [
- ['OS == "win"', {
+ ['OS == "win" or OS == "mac"', {
'dependencies': [
'../crypto/crypto.gyp:crypto',
],
@@ -52,8 +52,9 @@
'..'
],
'sources': [
+ 'attachment_broker_mac_unittest.cc',
+ 'attachment_broker_privileged_mac_unittest.cc',
'attachment_broker_privileged_win_unittest.cc',
- 'attachment_broker_unprivileged_win_unittest.cc',
'ipc_channel_posix_unittest.cc',
'ipc_channel_proxy_unittest.cc',
'ipc_channel_reader_unittest.cc',
@@ -154,6 +155,8 @@
'ipc_test_channel_listener.h',
'ipc_test_sink.cc',
'ipc_test_sink.h',
+ 'test_util_mac.cc',
+ 'test_util_mac.h',
],
},
],
@@ -211,9 +214,29 @@
'test_suite_name': 'ipc_perftests',
},
'includes': [ '../build/apk_test.gypi' ],
+ }
+ ],
+ 'conditions': [
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'ipc_tests_apk_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'ipc_tests_apk',
+ ],
+ 'includes': [
+ '../build/isolate.gypi',
+ ],
+ 'sources': [
+ 'ipc_tests_apk.isolate',
+ ],
+ },
+ ],
}],
+ ],
}],
- ['test_isolation_mode != "noop"', {
+ ['test_isolation_mode != "noop" and OS != "android"', {
'targets': [
{
'target_name': 'ipc_tests_run',
diff --git a/chromium/ipc/ipc.gypi b/chromium/ipc/ipc.gypi
index 696b34ad28e..dbd2099e4c3 100644
--- a/chromium/ipc/ipc.gypi
+++ b/chromium/ipc/ipc.gypi
@@ -16,14 +16,19 @@
'attachment_broker_messages.h',
'attachment_broker_privileged.cc',
'attachment_broker_privileged.h',
+ 'attachment_broker_privileged_mac.cc',
+ 'attachment_broker_privileged_mac.h',
'attachment_broker_privileged_win.cc',
'attachment_broker_privileged_win.h',
'attachment_broker_unprivileged.cc',
'attachment_broker_unprivileged.h',
+ 'attachment_broker_unprivileged_mac.cc',
+ 'attachment_broker_unprivileged_mac.h',
'attachment_broker_unprivileged_win.cc',
'attachment_broker_unprivileged_win.h',
'brokerable_attachment.cc',
'brokerable_attachment.h',
+ 'brokerable_attachment_mac.cc',
'brokerable_attachment_win.cc',
'handle_attachment_win.cc',
'handle_attachment_win.h',
diff --git a/chromium/ipc/ipc_channel.cc b/chromium/ipc/ipc_channel.cc
index 6772e1c5579..2d510478cc3 100644
--- a/chromium/ipc/ipc_channel.cc
+++ b/chromium/ipc/ipc_channel.cc
@@ -4,6 +4,7 @@
#include "ipc/ipc_channel.h"
+#include <stddef.h>
#include <stdint.h>
#include <limits>
@@ -11,6 +12,7 @@
#include "base/atomic_sequence_num.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
namespace {
diff --git a/chromium/ipc/ipc_channel.h b/chromium/ipc/ipc_channel.h
index ce3a00af19b..dd882bb5cc0 100644
--- a/chromium/ipc/ipc_channel.h
+++ b/chromium/ipc/ipc_channel.h
@@ -5,21 +5,23 @@
#ifndef IPC_IPC_CHANNEL_H_
#define IPC_IPC_CHANNEL_H_
+#include <stddef.h>
#include <stdint.h>
#include <string>
-#if defined(OS_POSIX)
-#include <sys/types.h>
-#endif
-
#include "base/compiler_specific.h"
#include "base/files/scoped_file.h"
#include "base/process/process.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_endpoint.h"
#include "ipc/ipc_message.h"
+#if defined(OS_POSIX)
+#include <sys/types.h>
+#endif
+
namespace IPC {
class Listener;
@@ -73,7 +75,7 @@ class IPC_EXPORT Channel : public Endpoint {
};
// Messages internal to the IPC implementation are defined here.
- // Uses Maximum value of message type (uint16), to avoid conflicting
+ // Uses Maximum value of message type (uint16_t), to avoid conflicting
// with normal message types, which are enumeration constants starting from 0.
enum {
// The Hello message is sent by the peer when the channel is connected.
@@ -97,6 +99,11 @@ class IPC_EXPORT Channel : public Endpoint {
// Amount of data to read at once from the pipe.
static const size_t kReadBufferSize = 4 * 1024;
+ // Maximum persistent read buffer size. Read buffer can grow larger to
+ // accommodate large messages, but it's recommended to shrink back to this
+ // value because it fits 99.9% of all messages (see issue 529940 for data).
+ static const size_t kMaximumReadBufferSize = 64 * 1024;
+
// Initialize a Channel.
//
// |channel_handle| identifies the communication Channel. For POSIX, if
@@ -239,10 +246,10 @@ class IPC_EXPORT Channel : public Endpoint {
~OutputElement();
size_t size() const { return message_ ? message_->size() : length_; }
const void* data() const { return message_ ? message_->data() : buffer_; }
- const Message* get_message() const { return message_.get(); }
+ Message* get_message() const { return message_.get(); }
private:
- scoped_ptr<const Message> message_;
+ scoped_ptr<Message> message_;
void* buffer_;
size_t length_;
};
diff --git a/chromium/ipc/ipc_channel_common.cc b/chromium/ipc/ipc_channel_common.cc
index f841dab8455..c12a360b64c 100644
--- a/chromium/ipc/ipc_channel_common.cc
+++ b/chromium/ipc/ipc_channel_common.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "build/build_config.h"
#include "ipc/ipc_channel.h"
namespace IPC {
diff --git a/chromium/ipc/ipc_channel_factory.cc b/chromium/ipc/ipc_channel_factory.cc
index 78cd3633a54..6dda14d273c 100644
--- a/chromium/ipc/ipc_channel_factory.cc
+++ b/chromium/ipc/ipc_channel_factory.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "ipc/ipc_channel_factory.h"
namespace IPC {
diff --git a/chromium/ipc/ipc_channel_nacl.cc b/chromium/ipc/ipc_channel_nacl.cc
index 798657ab4e4..84d77f68d07 100644
--- a/chromium/ipc/ipc_channel_nacl.cc
+++ b/chromium/ipc/ipc_channel_nacl.cc
@@ -13,6 +13,7 @@
#include "base/bind.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/task_runner_util.h"
@@ -286,7 +287,8 @@ bool ChannelNacl::ProcessOutgoingMessages() {
output_queue_.pop_front();
int fds[MessageAttachmentSet::kMaxDescriptorsPerMessage];
- const size_t num_fds = msg->attachment_set()->size();
+ const size_t num_fds =
+ msg->attachment_set()->num_non_brokerable_attachments();
DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage);
msg->attachment_set()->PeekDescriptors(fds);
@@ -308,7 +310,7 @@ bool ChannelNacl::ProcessOutgoingMessages() {
<< msg->size();
return false;
} else {
- msg->attachment_set()->CommitAll();
+ msg->attachment_set()->CommitAllDescriptors();
}
// Message sent OK!
diff --git a/chromium/ipc/ipc_channel_nacl.h b/chromium/ipc/ipc_channel_nacl.h
index b7e97ccf4a7..0fcf85af829 100644
--- a/chromium/ipc/ipc_channel_nacl.h
+++ b/chromium/ipc/ipc_channel_nacl.h
@@ -8,6 +8,7 @@
#include <deque>
#include <string>
+#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
diff --git a/chromium/ipc/ipc_channel_posix.cc b/chromium/ipc/ipc_channel_posix.cc
index 3f5771bc1b6..f53a8fe36ec 100644
--- a/chromium/ipc/ipc_channel_posix.cc
+++ b/chromium/ipc/ipc_channel_posix.cc
@@ -21,8 +21,10 @@
#include <sys/un.h>
#endif
+#include <algorithm>
#include <map>
#include <string>
+#include <utility>
#include "base/command_line.h"
#include "base/files/file_path.h"
@@ -38,6 +40,7 @@
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
+#include "build/build_config.h"
#include "ipc/attachment_broker.h"
#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_listener.h"
@@ -378,27 +381,28 @@ void ChannelPosix::CloseFileDescriptors(Message* msg) {
QueueCloseFDMessage(to_close[i], 2);
}
#else
- msg->attachment_set()->CommitAll();
+ msg->attachment_set()->CommitAllDescriptors();
#endif
}
bool ChannelPosix::ProcessOutgoingMessages() {
- DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
- // no connection?
+ if (waiting_connect_)
+ return true;
+ if (is_blocked_on_write_)
+ return true;
if (output_queue_.empty())
return true;
-
if (!pipe_.is_valid())
return false;
// Write out all the messages we can till the write blocks or there are no
// more outgoing messages.
while (!output_queue_.empty()) {
- Message* msg = output_queue_.front();
+ OutputElement* element = output_queue_.front();
- size_t amt_to_write = msg->size() - message_send_bytes_written_;
+ size_t amt_to_write = element->size() - message_send_bytes_written_;
DCHECK_NE(0U, amt_to_write);
- const char* out_bytes = reinterpret_cast<const char*>(msg->data()) +
+ const char* out_bytes = reinterpret_cast<const char*>(element->data()) +
message_send_bytes_written_;
struct msghdr msgh = {0};
@@ -411,10 +415,13 @@ bool ChannelPosix::ProcessOutgoingMessages() {
ssize_t bytes_written = 1;
int fd_written = -1;
- if (message_send_bytes_written_ == 0 && !msg->attachment_set()->empty()) {
+ Message* msg = element->get_message();
+ if (message_send_bytes_written_ == 0 && msg &&
+ msg->attachment_set()->num_non_brokerable_attachments()) {
// This is the first chunk of a message which has descriptors to send
struct cmsghdr *cmsg;
- const unsigned num_fds = msg->attachment_set()->size();
+ const unsigned num_fds =
+ msg->attachment_set()->num_non_brokerable_attachments();
DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage);
if (msg->attachment_set()->ContainsDirectoryDescriptor()) {
@@ -446,7 +453,7 @@ bool ChannelPosix::ProcessOutgoingMessages() {
fd_written = pipe_.get();
bytes_written = HANDLE_EINTR(sendmsg(pipe_.get(), &msgh, MSG_DONTWAIT));
}
- if (bytes_written > 0)
+ if (bytes_written > 0 && msg)
CloseFileDescriptors(msg);
if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) {
@@ -468,7 +475,7 @@ bool ChannelPosix::ProcessOutgoingMessages() {
PLOG(ERROR) << "pipe error on "
<< fd_written
<< " Currently writing message of size: "
- << msg->size();
+ << element->size();
return false;
}
@@ -491,8 +498,13 @@ bool ChannelPosix::ProcessOutgoingMessages() {
message_send_bytes_written_ = 0;
// Message sent OK!
- DVLOG(2) << "sent message @" << msg << " on channel @" << this
- << " with type " << msg->type() << " on fd " << pipe_.get();
+ if (msg) {
+ DVLOG(2) << "sent message @" << msg << " on channel @" << this
+ << " with type " << msg->type() << " on fd " << pipe_.get();
+ } else {
+ DVLOG(2) << "sent buffer @" << element->data() << " on channel @"
+ << this << " on fd " << pipe_.get();
+ }
delete output_queue_.front();
output_queue_.pop();
}
@@ -506,20 +518,18 @@ bool ChannelPosix::Send(Message* message) {
<< " with type " << message->type()
<< " (" << output_queue_.size() << " in queue)";
-#ifdef IPC_MESSAGE_LOG_ENABLED
- Logging::GetInstance()->OnSendMessage(message, "");
-#endif // IPC_MESSAGE_LOG_ENABLED
+ if (!prelim_queue_.empty()) {
+ prelim_queue_.push(message);
+ return true;
+ }
- TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
- "ChannelPosix::Send",
- message->flags(),
- TRACE_EVENT_FLAG_FLOW_OUT);
- output_queue_.push(message);
- if (!is_blocked_on_write_ && !waiting_connect_) {
- return ProcessOutgoingMessages();
+ if (message->HasBrokerableAttachments() &&
+ peer_pid_ == base::kNullProcessId) {
+ prelim_queue_.push(message);
+ return true;
}
- return true;
+ return ProcessMessageForDelivery(message);
}
AttachmentBroker* ChannelPosix::GetAttachmentBroker() {
@@ -536,7 +546,7 @@ base::ScopedFD ChannelPosix::TakeClientFileDescriptor() {
if (!client_pipe_.is_valid())
return base::ScopedFD();
PipeMap::GetInstance()->Remove(pipe_name_);
- return client_pipe_.Pass();
+ return std::move(client_pipe_);
}
void ChannelPosix::CloseClientFileDescriptor() {
@@ -570,10 +580,11 @@ void ChannelPosix::ResetToAcceptingConnectionState() {
ResetSafely(&pipe_);
while (!output_queue_.empty()) {
- Message* m = output_queue_.front();
+ OutputElement* element = output_queue_.front();
output_queue_.pop();
- CloseFileDescriptors(m);
- delete m;
+ if (element->get_message())
+ CloseFileDescriptors(element->get_message());
+ delete element;
}
// Close any outstanding, received file descriptors.
@@ -668,10 +679,8 @@ void ChannelPosix::OnFileCanReadWithoutBlocking(int fd) {
// only send our handshake message after we've processed the client's.
// This gives us a chance to kill the client if the incoming handshake
// is invalid. This also flushes any closefd messages.
- if (!is_blocked_on_write_) {
- if (!ProcessOutgoingMessages()) {
- ClosePipeOnError();
- }
+ if (!ProcessOutgoingMessages()) {
+ ClosePipeOnError();
}
}
@@ -684,6 +693,72 @@ void ChannelPosix::OnFileCanWriteWithoutBlocking(int fd) {
}
}
+bool ChannelPosix::ProcessMessageForDelivery(Message* message) {
+ // Sending a brokerable attachment requires a call to Channel::Send(), so
+ // Send() may be re-entrant.
+ if (message->HasBrokerableAttachments()) {
+ DCHECK(GetAttachmentBroker());
+ DCHECK(peer_pid_ != base::kNullProcessId);
+ for (const scoped_refptr<IPC::BrokerableAttachment>& attachment :
+ message->attachment_set()->GetBrokerableAttachments()) {
+ if (!GetAttachmentBroker()->SendAttachmentToProcess(attachment,
+ peer_pid_)) {
+ delete message;
+ return false;
+ }
+ }
+ }
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ Logging::GetInstance()->OnSendMessage(message, "");
+#endif // IPC_MESSAGE_LOG_ENABLED
+
+ TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
+ "ChannelPosix::Send",
+ message->flags(),
+ TRACE_EVENT_FLAG_FLOW_OUT);
+
+ // |output_queue_| takes ownership of |message|.
+ OutputElement* element = new OutputElement(message);
+ output_queue_.push(element);
+
+ if (message->HasBrokerableAttachments()) {
+ // |output_queue_| takes ownership of |ids.buffer|.
+ Message::SerializedAttachmentIds ids =
+ message->SerializedIdsOfBrokerableAttachments();
+ output_queue_.push(new OutputElement(ids.buffer, ids.size));
+ }
+
+ return ProcessOutgoingMessages();
+}
+
+bool ChannelPosix::FlushPrelimQueue() {
+ DCHECK_NE(peer_pid_, base::kNullProcessId);
+
+ // Due to the possibly re-entrant nature of ProcessMessageForDelivery(),
+ // |prelim_queue_| should appear empty.
+ std::queue<Message*> prelim_queue;
+ std::swap(prelim_queue_, prelim_queue);
+
+ bool processing_error = false;
+ while (!prelim_queue.empty()) {
+ Message* m = prelim_queue.front();
+ processing_error = !ProcessMessageForDelivery(m);
+ prelim_queue.pop();
+ if (processing_error)
+ break;
+ }
+
+ // Delete any unprocessed messages.
+ while (!prelim_queue.empty()) {
+ Message* m = prelim_queue.front();
+ delete m;
+ prelim_queue.pop();
+ }
+
+ return !processing_error;
+}
+
bool ChannelPosix::AcceptConnection() {
base::MessageLoopForIO::current()->WatchFileDescriptor(
pipe_.get(),
@@ -747,7 +822,8 @@ void ChannelPosix::QueueHelloMessage() {
if (!msg->WriteInt(GetHelloMessageProcId())) {
NOTREACHED() << "Unable to pickle hello message proc id";
}
- output_queue_.push(msg.release());
+ OutputElement* element = new OutputElement(msg.release());
+ output_queue_.push(element);
}
ChannelPosix::ReadState ChannelPosix::ReadData(
@@ -902,8 +978,9 @@ void ChannelPosix::QueueCloseFDMessage(int fd, int hops) {
if (!msg->WriteInt(hops - 1) || !msg->WriteInt(fd)) {
NOTREACHED() << "Unable to pickle close fd.";
}
- // Send(msg.release());
- output_queue_.push(msg.release());
+
+ OutputElement* element = new OutputElement(msg.release());
+ output_queue_.push(element);
break;
}
@@ -929,6 +1006,9 @@ void ChannelPosix::HandleInternalMessage(const Message& msg) {
peer_pid_ = pid;
listener()->OnChannelConnected(pid);
+
+ if (!FlushPrelimQueue())
+ ClosePipeOnError();
break;
#if defined(OS_MACOSX)
diff --git a/chromium/ipc/ipc_channel_posix.h b/chromium/ipc/ipc_channel_posix.h
index be47705db01..ddeb60ea365 100644
--- a/chromium/ipc/ipc_channel_posix.h
+++ b/chromium/ipc/ipc_channel_posix.h
@@ -7,6 +7,7 @@
#include "ipc/ipc_channel.h"
+#include <stddef.h>
#include <sys/socket.h> // for CMSG macros
#include <queue>
@@ -15,8 +16,10 @@
#include <vector>
#include "base/files/scoped_file.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel_reader.h"
#include "ipc/ipc_message_attachment_set.h"
@@ -67,6 +70,13 @@ class IPC_EXPORT ChannelPosix : public Channel,
private:
bool CreatePipe(const IPC::ChannelHandle& channel_handle);
+ // Returns false on recoverable error.
+ // There are two reasons why this method might leave messages in the
+ // output_queue_.
+ // 1. |waiting_connect_| is |true|.
+ // 2. |is_blocked_on_write_| is |true|.
+ // If any of these conditionals change, this method should be called, as
+ // previously blocked messages may no longer be blocked.
bool ProcessOutgoingMessages();
bool AcceptConnection();
@@ -100,6 +110,18 @@ class IPC_EXPORT ChannelPosix : public Channel,
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
+ // Returns |false| on channel error.
+ // If |message| has brokerable attachments, those attachments are passed to
+ // the AttachmentBroker (which in turn invokes Send()), so this method must
+ // be re-entrant.
+ // Adds |message| to |output_queue_| and calls ProcessOutgoingMessages().
+ bool ProcessMessageForDelivery(Message* message);
+
+ // Moves all messages from |prelim_queue_| to |output_queue_| by calling
+ // ProcessMessageForDelivery().
+ // Returns |false| on channel error.
+ bool FlushPrelimQueue();
+
Mode mode_;
base::ProcessId peer_pid_;
@@ -135,8 +157,18 @@ class IPC_EXPORT ChannelPosix : public Channel,
// the pipe. On POSIX it's used as a key in a local map of file descriptors.
std::string pipe_name_;
+ // Messages not yet ready to be sent are queued here. Messages removed from
+ // this queue are placed in the output_queue_. The double queue is
+ // unfortunate, but is necessary because messages with brokerable attachments
+ // can generate multiple messages to be sent (possibly from other channels).
+ // Some of these generated messages cannot be sent until |peer_pid_| has been
+ // configured.
+ // As soon as |peer_pid| has been configured, there is no longer any need for
+ // |prelim_queue_|. All messages are flushed, and no new messages are added.
+ std::queue<Message*> prelim_queue_;
+
// Messages to be sent are queued here.
- std::queue<Message*> output_queue_;
+ std::queue<OutputElement*> output_queue_;
// We assume a worst case: kReadBufferSize bytes of messages, where each
// message has no payload and a full complement of descriptors.
diff --git a/chromium/ipc/ipc_channel_posix_unittest.cc b/chromium/ipc/ipc_channel_posix_unittest.cc
index 99bd68b5e3f..c122b719508 100644
--- a/chromium/ipc/ipc_channel_posix_unittest.cc
+++ b/chromium/ipc/ipc_channel_posix_unittest.cc
@@ -6,8 +6,11 @@
#include "ipc/ipc_channel_posix.h"
+#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <stdint.h>
+#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
@@ -22,6 +25,7 @@
#include "base/single_thread_task_runner.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
+#include "build/build_config.h"
#include "ipc/ipc_listener.h"
#include "ipc/unix_domain_socket_util.h"
#include "testing/multiprocess_func_list.h"
@@ -89,7 +93,7 @@ class IPCChannelPosixTestListener : public IPC::Listener {
loop->QuitNow();
} else {
// Die as soon as Run is called.
- loop->task_runner()->PostTask(FROM_HERE, loop->QuitClosure());
+ loop->task_runner()->PostTask(FROM_HERE, loop->QuitWhenIdleClosure());
}
}
@@ -189,7 +193,8 @@ 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->task_runner()->PostDelayedTask(FROM_HERE, loop->QuitClosure(), delay);
+ loop->task_runner()->PostDelayedTask(FROM_HERE, loop->QuitWhenIdleClosure(),
+ delay);
loop->Run();
}
diff --git a/chromium/ipc/ipc_channel_proxy.cc b/chromium/ipc/ipc_channel_proxy.cc
index 84f87fc8733..5e702617e0d 100644
--- a/chromium/ipc/ipc_channel_proxy.cc
+++ b/chromium/ipc/ipc_channel_proxy.cc
@@ -4,6 +4,10 @@
#include "ipc/ipc_channel_proxy.h"
+#include <stddef.h>
+#include <stdint.h>
+#include <utility>
+
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/location.h"
@@ -12,6 +16,7 @@
#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel_factory.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_logging.h"
@@ -355,7 +360,7 @@ scoped_ptr<ChannelProxy> ChannelProxy::Create(
const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
scoped_ptr<ChannelProxy> channel(new ChannelProxy(listener, ipc_task_runner));
channel->Init(channel_handle, mode, true);
- return channel.Pass();
+ return channel;
}
// static
@@ -364,8 +369,8 @@ scoped_ptr<ChannelProxy> ChannelProxy::Create(
Listener* listener,
const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
scoped_ptr<ChannelProxy> channel(new ChannelProxy(listener, ipc_task_runner));
- channel->Init(factory.Pass(), true);
- return channel.Pass();
+ channel->Init(std::move(factory), true);
+ return channel;
}
ChannelProxy::ChannelProxy(Context* context)
@@ -416,11 +421,11 @@ void ChannelProxy::Init(scoped_ptr<ChannelFactory> factory,
// low-level pipe so that the client can connect. Without creating
// the pipe immediately, it is possible for a listener to attempt
// to connect and get an error since the pipe doesn't exist yet.
- context_->CreateChannel(factory.Pass());
+ context_->CreateChannel(std::move(factory));
} else {
context_->ipc_task_runner()->PostTask(
- FROM_HERE, base::Bind(&Context::CreateChannel,
- context_.get(), Passed(factory.Pass())));
+ FROM_HERE, base::Bind(&Context::CreateChannel, context_.get(),
+ base::Passed(&factory)));
}
// complete initialization on the background thread
diff --git a/chromium/ipc/ipc_channel_proxy.h b/chromium/ipc/ipc_channel_proxy.h
index f2eb82beba3..9fdffb1ca57 100644
--- a/chromium/ipc/ipc_channel_proxy.h
+++ b/chromium/ipc/ipc_channel_proxy.h
@@ -5,12 +5,15 @@
#ifndef IPC_IPC_CHANNEL_PROXY_H_
#define IPC_IPC_CHANNEL_PROXY_H_
+#include <stdint.h>
+
#include <vector>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/non_thread_safe.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_endpoint.h"
@@ -215,6 +218,8 @@ class IPC_EXPORT ChannelProxy : public Endpoint, public base::NonThreadSafe {
void set_attachment_broker_endpoint(bool is_endpoint) {
attachment_broker_endpoint_ = is_endpoint;
+ if (channel_)
+ channel_->SetAttachmentBrokerEndpoint(is_endpoint);
}
// Methods called on the IO thread.
diff --git a/chromium/ipc/ipc_channel_proxy_unittest.cc b/chromium/ipc/ipc_channel_proxy_unittest.cc
index 7c5c8a70fca..f7f832b1445 100644
--- a/chromium/ipc/ipc_channel_proxy_unittest.cc
+++ b/chromium/ipc/ipc_channel_proxy_unittest.cc
@@ -4,6 +4,9 @@
#include "build/build_config.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/pickle.h"
#include "base/threading/thread.h"
#include "ipc/ipc_message.h"
diff --git a/chromium/ipc/ipc_channel_reader.cc b/chromium/ipc/ipc_channel_reader.cc
index 5ca0e46dd5a..9c6af49f2f1 100644
--- a/chromium/ipc/ipc_channel_reader.cc
+++ b/chromium/ipc/ipc_channel_reader.cc
@@ -4,8 +4,11 @@
#include "ipc/ipc_channel_reader.h"
+#include <stddef.h>
+
#include <algorithm>
+#include "base/message_loop/message_loop.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_logging.h"
#include "ipc/ipc_message.h"
@@ -15,7 +18,9 @@
namespace IPC {
namespace internal {
-ChannelReader::ChannelReader(Listener* listener) : listener_(listener) {
+ChannelReader::ChannelReader(Listener* listener)
+ : listener_(listener),
+ max_input_buffer_size_(Channel::kMaximumReadBufferSize) {
memset(input_buf_, 0, sizeof(input_buf_));
}
@@ -68,6 +73,12 @@ void ChannelReader::CleanUp() {
}
}
+void ChannelReader::DispatchMessage(Message* m) {
+ EmitLogBeforeDispatch(*m);
+ listener_->OnMessageReceived(*m);
+ HandleDispatchError(*m);
+}
+
bool ChannelReader::TranslateInputData(const char* input_data,
int input_data_len) {
const char* p;
@@ -95,33 +106,9 @@ bool ChannelReader::TranslateInputData(const char* input_data,
int pickle_len = static_cast<int>(info.pickle_end - p);
Message translated_message(p, pickle_len);
- for (const auto& id : info.attachment_ids)
- translated_message.AddPlaceholderBrokerableAttachmentWithId(id);
-
- if (!GetNonBrokeredAttachments(&translated_message))
+ if (!HandleTranslatedMessage(&translated_message, info.attachment_ids))
return false;
- // If there are no queued messages, attempt to immediately dispatch the
- // newly translated message.
- if (queued_messages_.empty()) {
- DCHECK(blocked_ids_.empty());
- AttachmentIdSet blocked_ids =
- GetBrokeredAttachments(&translated_message);
-
- if (blocked_ids.empty()) {
- // Dispatch the message and continue the loop.
- DispatchMessage(&translated_message);
- p = info.message_end;
- continue;
- }
-
- blocked_ids_.swap(blocked_ids);
- StartObservingAttachmentBroker();
- }
-
- // Make a deep copy of |translated_message| to add to the queue.
- scoped_ptr<Message> m(new Message(translated_message));
- queued_messages_.push_back(m.release());
p = info.message_end;
} else {
// Last message is partial.
@@ -132,25 +119,135 @@ bool ChannelReader::TranslateInputData(const char* input_data,
}
}
+ // Account for the case where last message's byte is in the next data chunk.
+ size_t next_message_buffer_size = next_message_size ?
+ next_message_size + Channel::kReadBufferSize - 1:
+ 0;
+
// Save any partial data in the overflow buffer.
- input_overflow_buf_.assign(p, end - p);
+ if (p != input_overflow_buf_.data())
+ input_overflow_buf_.assign(p, end - p);
if (!input_overflow_buf_.empty()) {
// We have something in the overflow buffer, which means that we will
// append the next data chunk (instead of parsing it directly). So we
// resize the buffer to fit the next message, to avoid repeatedly
// growing the buffer as we receive all message' data chunks.
- next_message_size += Channel::kReadBufferSize - 1;
- if (next_message_size > input_overflow_buf_.capacity()) {
- input_overflow_buf_.reserve(next_message_size);
+ if (next_message_buffer_size > input_overflow_buf_.capacity()) {
+ input_overflow_buf_.reserve(next_message_buffer_size);
}
}
+ // Trim the buffer if we can
+ if (next_message_buffer_size < max_input_buffer_size_ &&
+ input_overflow_buf_.size() < max_input_buffer_size_ &&
+ input_overflow_buf_.capacity() > max_input_buffer_size_) {
+ // std::string doesn't really have a method to shrink capacity to
+ // a specific value, so we have to swap with another string.
+ std::string trimmed_buf;
+ trimmed_buf.reserve(max_input_buffer_size_);
+ if (trimmed_buf.capacity() > max_input_buffer_size_) {
+ // Since we don't control how much space reserve() actually reserves,
+ // we have to go other way around and change the max size to avoid
+ // getting into the outer if() again.
+ max_input_buffer_size_ = trimmed_buf.capacity();
+ }
+ trimmed_buf.assign(input_overflow_buf_.data(),
+ input_overflow_buf_.size());
+ input_overflow_buf_.swap(trimmed_buf);
+ }
+
if (input_overflow_buf_.empty() && !DidEmptyInputBuffers())
return false;
return true;
}
+bool ChannelReader::HandleTranslatedMessage(
+ Message* translated_message,
+ const AttachmentIdVector& attachment_ids) {
+ // Immediately handle internal messages.
+ if (IsInternalMessage(*translated_message)) {
+ EmitLogBeforeDispatch(*translated_message);
+ HandleInternalMessage(*translated_message);
+ HandleDispatchError(*translated_message);
+ return true;
+ }
+
+ translated_message->set_sender_pid(GetSenderPID());
+
+ // Immediately handle attachment broker messages.
+ if (DispatchAttachmentBrokerMessage(*translated_message)) {
+ // Ideally, the log would have been emitted prior to dispatching the
+ // message, but that would require this class to know more about the
+ // internals of attachment brokering, which should be avoided.
+ EmitLogBeforeDispatch(*translated_message);
+ HandleDispatchError(*translated_message);
+ return true;
+ }
+
+ return HandleExternalMessage(translated_message, attachment_ids);
+}
+
+bool ChannelReader::HandleExternalMessage(
+ Message* external_message,
+ const AttachmentIdVector& attachment_ids) {
+ for (const auto& id : attachment_ids)
+ external_message->AddPlaceholderBrokerableAttachmentWithId(id);
+
+ if (!GetNonBrokeredAttachments(external_message))
+ return false;
+
+ // If there are no queued messages, attempt to immediately dispatch the
+ // newly translated message.
+ if (queued_messages_.empty()) {
+ DCHECK(blocked_ids_.empty());
+ AttachmentIdSet blocked_ids = GetBrokeredAttachments(external_message);
+
+ if (blocked_ids.empty()) {
+ DispatchMessage(external_message);
+ return true;
+ }
+
+ blocked_ids_.swap(blocked_ids);
+ StartObservingAttachmentBroker();
+ }
+
+ // Make a deep copy of |external_message| to add to the queue.
+ scoped_ptr<Message> m(new Message(*external_message));
+ queued_messages_.push_back(m.release());
+ return true;
+}
+
+void ChannelReader::HandleDispatchError(const Message& message) {
+ if (message.dispatch_error())
+ listener_->OnBadMessageReceived(message);
+}
+
+void ChannelReader::EmitLogBeforeDispatch(const Message& message) {
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ std::string name;
+ Logging::GetInstance()->GetMessageText(message.type(), &name, &message, NULL);
+ TRACE_EVENT_WITH_FLOW1("ipc,toplevel", "ChannelReader::DispatchInputData",
+ message.flags(), TRACE_EVENT_FLAG_FLOW_IN, "name",
+ name);
+#else
+ TRACE_EVENT_WITH_FLOW2("ipc,toplevel", "ChannelReader::DispatchInputData",
+ message.flags(), TRACE_EVENT_FLAG_FLOW_IN, "class",
+ IPC_MESSAGE_ID_CLASS(message.type()), "line",
+ IPC_MESSAGE_ID_LINE(message.type()));
+#endif
+}
+
+bool ChannelReader::DispatchAttachmentBrokerMessage(const Message& message) {
+#if USE_ATTACHMENT_BROKER
+ if (IsAttachmentBrokerEndpoint() && GetAttachmentBroker()) {
+ return GetAttachmentBroker()->OnMessageReceived(message);
+ }
+#endif // USE_ATTACHMENT_BROKER
+
+ return false;
+}
+
ChannelReader::DispatchState ChannelReader::DispatchMessages() {
while (!queued_messages_.empty()) {
if (!blocked_ids_.empty())
@@ -171,53 +268,18 @@ ChannelReader::DispatchState ChannelReader::DispatchMessages() {
return DISPATCH_FINISHED;
}
-void ChannelReader::DispatchMessage(Message* m) {
- m->set_sender_pid(GetSenderPID());
-
-#ifdef IPC_MESSAGE_LOG_ENABLED
- std::string name;
- Logging::GetInstance()->GetMessageText(m->type(), &name, m, NULL);
- TRACE_EVENT_WITH_FLOW1("ipc,toplevel",
- "ChannelReader::DispatchInputData",
- m->flags(),
- TRACE_EVENT_FLAG_FLOW_IN,
- "name", name);
-#else
- TRACE_EVENT_WITH_FLOW2("ipc,toplevel",
- "ChannelReader::DispatchInputData",
- m->flags(),
- TRACE_EVENT_FLAG_FLOW_IN,
- "class", IPC_MESSAGE_ID_CLASS(m->type()),
- "line", IPC_MESSAGE_ID_LINE(m->type()));
-#endif
-
- bool handled = false;
- if (IsInternalMessage(*m)) {
- HandleInternalMessage(*m);
- handled = true;
- }
-#if USE_ATTACHMENT_BROKER
- if (!handled && IsAttachmentBrokerEndpoint() && GetAttachmentBroker()) {
- handled = GetAttachmentBroker()->OnMessageReceived(*m);
- }
-#endif // USE_ATTACHMENT_BROKER
- if (!handled)
- listener_->OnMessageReceived(*m);
- if (m->dispatch_error())
- listener_->OnBadMessageReceived(*m);
-}
-
ChannelReader::AttachmentIdSet ChannelReader::GetBrokeredAttachments(
Message* msg) {
std::set<BrokerableAttachment::AttachmentId> blocked_ids;
#if USE_ATTACHMENT_BROKER
MessageAttachmentSet* set = msg->attachment_set();
- std::vector<const BrokerableAttachment*> brokerable_attachments_copy =
- set->PeekBrokerableAttachments();
- for (const BrokerableAttachment* attachment : brokerable_attachments_copy) {
+ std::vector<scoped_refptr<IPC::BrokerableAttachment>>
+ brokerable_attachments_copy(set->GetBrokerableAttachments());
+ for (const auto& attachment : brokerable_attachments_copy) {
if (attachment->NeedsBrokering()) {
AttachmentBroker* broker = GetAttachmentBroker();
+ DCHECK(broker);
scoped_refptr<BrokerableAttachment> brokered_attachment;
bool result = broker->GetAttachmentWithId(attachment->GetIdentifier(),
&brokered_attachment);
@@ -251,7 +313,8 @@ void ChannelReader::ReceivedBrokerableAttachmentWithId(
void ChannelReader::StartObservingAttachmentBroker() {
#if USE_ATTACHMENT_BROKER
- GetAttachmentBroker()->AddObserver(this);
+ GetAttachmentBroker()->AddObserver(
+ this, base::MessageLoopForIO::current()->task_runner());
#endif // USE_ATTACHMENT_BROKER
}
diff --git a/chromium/ipc/ipc_channel_reader.h b/chromium/ipc/ipc_channel_reader.h
index 46775226f9a..ca2bd9476e5 100644
--- a/chromium/ipc/ipc_channel_reader.h
+++ b/chromium/ipc/ipc_channel_reader.h
@@ -5,6 +5,8 @@
#ifndef IPC_IPC_CHANNEL_READER_H_
#define IPC_IPC_CHANNEL_READER_H_
+#include <stddef.h>
+
#include <set>
#include "base/gtest_prod_util.h"
@@ -129,17 +131,42 @@ class IPC_EXPORT ChannelReader : public SupportsAttachmentBrokering,
FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, AttachmentNotYetBrokered);
FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, ResizeOverflowBuffer);
FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, InvalidMessageSize);
+ FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, TrimBuffer);
- typedef std::set<BrokerableAttachment::AttachmentId> AttachmentIdSet;
+ using AttachmentIdSet = std::set<BrokerableAttachment::AttachmentId>;
+ using AttachmentIdVector = std::vector<BrokerableAttachment::AttachmentId>;
- // Takes the given data received from the IPC channel, translates it into
- // Messages, and puts them in queued_messages_.
- // As an optimization, after a message is translated, the message is
- // immediately dispatched if able. This prevents an otherwise unnecessary deep
- // copy of the message which is needed to store the message in the message
- // queue.
+ // Takes the data received from the IPC channel and translates it into
+ // Messages. Complete messages are passed to HandleTranslatedMessage().
+ // Returns |false| on unrecoverable error.
bool TranslateInputData(const char* input_data, int input_data_len);
+ // Internal messages and messages bound for the attachment broker are
+ // immediately dispatched. Other messages are passed to
+ // HandleExternalMessage().
+ // Returns |false| on unrecoverable error.
+ bool HandleTranslatedMessage(Message* translated_message,
+ const AttachmentIdVector& attachment_ids);
+
+ // Populates the message with brokered and non-brokered attachments. If
+ // possible, the message is immediately dispatched. Otherwise, a deep copy of
+ // the message is added to |queued_messages_|. |blocked_ids_| are updated if
+ // necessary.
+ bool HandleExternalMessage(Message* external_message,
+ const AttachmentIdVector& attachment_ids);
+
+ // If there was a dispatch error, informs |listener_|.
+ void HandleDispatchError(const Message& message);
+
+ // Emits logging associated with a Message that is about to be dispatched.
+ void EmitLogBeforeDispatch(const Message& message);
+
+ // Attachment broker messages should be dispatched out of band, since there
+ // are no ordering restrictions on them, and they may be required to dispatch
+ // the messages waiting in |queued_messages_|.
+ // Returns true if the attachment broker handled |message|.
+ bool DispatchAttachmentBrokerMessage(const Message& message);
+
// Dispatches messages from queued_messages_ to listeners. Successfully
// dispatched messages are removed from queued_messages_.
DispatchState DispatchMessages();
@@ -171,6 +198,11 @@ class IPC_EXPORT ChannelReader : public SupportsAttachmentBrokering,
// this buffer.
std::string input_overflow_buf_;
+ // Maximum overflow buffer size, see Channel::kMaximumReadBufferSize.
+ // This is not a constant because we update it to reflect the reality
+ // of std::string::reserve() implementation.
+ size_t max_input_buffer_size_;
+
// These messages are waiting to be dispatched. If this vector is non-empty,
// then the front Message must be blocked on receiving an attachment from the
// AttachmentBroker.
diff --git a/chromium/ipc/ipc_channel_reader_unittest.cc b/chromium/ipc/ipc_channel_reader_unittest.cc
index 7728a817377..4ec71b53676 100644
--- a/chromium/ipc/ipc_channel_reader_unittest.cc
+++ b/chromium/ipc/ipc_channel_reader_unittest.cc
@@ -4,15 +4,27 @@
#include "build/build_config.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <limits>
#include <set>
+#include "base/run_loop.h"
#include "ipc/attachment_broker.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_channel_reader.h"
#include "ipc/placeholder_brokerable_attachment.h"
#include "testing/gtest/include/gtest/gtest.h"
+// Whether IPC::Message::FindNext() can determine message size for
+// partial messages. The condition is from FindNext() implementation.
+#if USE_ATTACHMENT_BROKER
+#define MESSAGE_FINDNEXT_PARTIAL 0
+#else
+#define MESSAGE_FINDNEXT_PARTIAL 1
+#endif
+
namespace IPC {
namespace internal {
@@ -42,8 +54,9 @@ class MockAttachmentBroker : public AttachmentBroker {
public:
typedef std::set<scoped_refptr<BrokerableAttachment>> AttachmentSet;
- bool SendAttachmentToProcess(const BrokerableAttachment* attachment,
- base::ProcessId destination_process) override {
+ bool SendAttachmentToProcess(
+ const scoped_refptr<BrokerableAttachment>& attachment,
+ base::ProcessId destination_process) override {
return false;
}
@@ -63,7 +76,14 @@ class MockChannelReader : public ChannelReader {
: ChannelReader(nullptr), last_dispatched_message_(nullptr) {}
ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) override {
- return READ_FAILED;
+ if (data_.empty())
+ return READ_PENDING;
+
+ size_t read_len = std::min(static_cast<size_t>(buffer_len), data_.size());
+ memcpy(buffer, data_.data(), read_len);
+ *bytes_read = static_cast<int>(read_len);
+ data_.erase(0, read_len);
+ return READ_SUCCEEDED;
}
bool ShouldDispatchInputMessage(Message* msg) override { return true; }
@@ -91,9 +111,18 @@ class MockChannelReader : public ChannelReader {
void set_broker(AttachmentBroker* broker) { broker_ = broker; }
+ void AppendData(const void* data, size_t size) {
+ data_.append(static_cast<const char*>(data), size);
+ }
+
+ void AppendMessageData(const Message& message) {
+ AppendData(message.data(), message.size());
+ }
+
private:
Message* last_dispatched_message_;
AttachmentBroker* broker_;
+ std::string data_;
};
class ExposedMessage: public Message {
@@ -102,6 +131,9 @@ class ExposedMessage: public Message {
using Message::header;
};
+// Payload that makes messages large
+const size_t LargePayloadSize = Channel::kMaximumReadBufferSize * 3 / 2;
+
} // namespace
#if USE_ATTACHMENT_BROKER
@@ -123,6 +155,8 @@ TEST(ChannelReaderTest, AttachmentAlreadyBrokered) {
}
TEST(ChannelReaderTest, AttachmentNotYetBrokered) {
+ scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoopForIO());
+
MockAttachmentBroker broker;
MockChannelReader reader;
reader.set_broker(&broker);
@@ -138,6 +172,9 @@ TEST(ChannelReaderTest, AttachmentNotYetBrokered) {
EXPECT_EQ(nullptr, reader.get_last_dispatched_message());
broker.AddAttachment(attachment);
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
EXPECT_EQ(m, reader.get_last_dispatched_message());
}
@@ -182,7 +219,7 @@ TEST(ChannelReaderTest, InvalidMessageSize) {
reinterpret_cast<const char*>(&header), sizeof(header)));
EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
- // Payload size is maximum int32 value
+ // Payload size is maximum int32_t value
header.payload_size = std::numeric_limits<int32_t>::max();
EXPECT_FALSE(reader.TranslateInputData(
reinterpret_cast<const char*>(&header), sizeof(header)));
@@ -191,5 +228,155 @@ TEST(ChannelReaderTest, InvalidMessageSize) {
#endif // !USE_ATTACHMENT_BROKER
+TEST(ChannelReaderTest, TrimBuffer) {
+ // ChannelReader uses std::string as a buffer, and calls reserve()
+ // to trim it to kMaximumReadBufferSize. However, an implementation
+ // is free to actually reserve a larger amount.
+ size_t trimmed_buffer_size;
+ {
+ std::string buf;
+ buf.reserve(Channel::kMaximumReadBufferSize);
+ trimmed_buffer_size = buf.capacity();
+ }
+
+ // Buffer is trimmed after message is processed.
+ {
+ MockChannelReader reader;
+
+ Message message;
+ message.WriteString(std::string(LargePayloadSize, 'X'));
+
+ // Sanity check
+ EXPECT_TRUE(message.size() > trimmed_buffer_size);
+
+ // Initially buffer is small
+ EXPECT_LE(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
+
+ // Write and process large message
+ reader.AppendMessageData(message);
+ EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
+ reader.ProcessIncomingMessages());
+
+ // After processing large message buffer is trimmed
+ EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
+ }
+
+ // Buffer is trimmed only after entire message is processed.
+ {
+ MockChannelReader reader;
+
+ ExposedMessage message;
+ message.WriteString(std::string(LargePayloadSize, 'X'));
+
+ // Write and process message header
+ reader.AppendData(message.header(), sizeof(ExposedMessage::Header));
+ EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
+ reader.ProcessIncomingMessages());
+
+#if MESSAGE_FINDNEXT_PARTIAL
+ // We determined message size for the message from its header, so
+ // we resized the buffer to fit.
+ EXPECT_GE(reader.input_overflow_buf_.capacity(), message.size());
+#else
+ // We couldn't determine message size, so we didn't resize the buffer.
+#endif
+
+ // Write and process payload
+ reader.AppendData(message.payload(), message.payload_size());
+ EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
+ reader.ProcessIncomingMessages());
+
+ // But once we process the message, we trim the buffer
+ EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
+ }
+
+ // Buffer is not trimmed if the next message is also large.
+ {
+ MockChannelReader reader;
+
+ // Write large message
+ Message message1;
+ message1.WriteString(std::string(LargePayloadSize * 2, 'X'));
+ reader.AppendMessageData(message1);
+
+ // Write header for the next large message
+ ExposedMessage message2;
+ message2.WriteString(std::string(LargePayloadSize, 'Y'));
+ reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
+
+ // Process messages
+ EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
+ reader.ProcessIncomingMessages());
+
+#if MESSAGE_FINDNEXT_PARTIAL
+ // We determined message size for the second (partial) message, so
+ // we resized the buffer to fit.
+ EXPECT_GE(reader.input_overflow_buf_.capacity(), message1.size());
+#else
+ // We couldn't determine message size for the second (partial) message,
+ // so we trimmed the buffer.
+ EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
+#endif
+ }
+
+ // Buffer resized appropriately if next message is larger than the first.
+ // (Similar to the test above except for the order of messages.)
+ {
+ MockChannelReader reader;
+
+ // Write large message
+ Message message1;
+ message1.WriteString(std::string(LargePayloadSize, 'Y'));
+ reader.AppendMessageData(message1);
+
+ // Write header for the next even larger message
+ ExposedMessage message2;
+ message2.WriteString(std::string(LargePayloadSize * 2, 'X'));
+ reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
+
+ // Process messages
+ EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
+ reader.ProcessIncomingMessages());
+
+#if MESSAGE_FINDNEXT_PARTIAL
+ // We determined message size for the second (partial) message, and
+ // resized the buffer to fit it.
+ EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
+#else
+ // We couldn't determine message size for the second (partial) message,
+ // so we trimmed the buffer.
+ EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
+#endif
+ }
+
+ // Buffer is not trimmed if we've just resized it to accommodate large
+ // incoming message.
+ {
+ MockChannelReader reader;
+
+ // Write small message
+ Message message1;
+ message1.WriteString(std::string(11, 'X'));
+ reader.AppendMessageData(message1);
+
+ // Write header for the next large message
+ ExposedMessage message2;
+ message2.WriteString(std::string(LargePayloadSize, 'Y'));
+ reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
+
+ EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
+ reader.ProcessIncomingMessages());
+
+#if MESSAGE_FINDNEXT_PARTIAL
+ // We determined message size for the second (partial) message, so
+ // we resized the buffer to fit.
+ EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
+#else
+ // We couldn't determine size for the second (partial) message, and
+ // first message was small, so we did nothing.
+#endif
+ }
+}
+
} // namespace internal
} // namespace IPC
diff --git a/chromium/ipc/ipc_channel_unittest.cc b/chromium/ipc/ipc_channel_unittest.cc
index 0c444fff3ee..0a49ca9abe0 100644
--- a/chromium/ipc/ipc_channel_unittest.cc
+++ b/chromium/ipc/ipc_channel_unittest.cc
@@ -8,6 +8,8 @@
#include <windows.h>
#endif
+#include <stdint.h>
+
#include <string>
#include "base/pickle.h"
diff --git a/chromium/ipc/ipc_channel_win.cc b/chromium/ipc/ipc_channel_win.cc
index e758d944d9e..62918627c17 100644
--- a/chromium/ipc/ipc_channel_win.cc
+++ b/chromium/ipc/ipc_channel_win.cc
@@ -4,8 +4,9 @@
#include "ipc/ipc_channel_win.h"
-#include <stdint.h>
#include <windows.h>
+#include <stddef.h>
+#include <stdint.h>
#include "base/auto_reset.h"
#include "base/bind.h"
@@ -103,13 +104,12 @@ bool ChannelWin::Send(Message* message) {
bool ChannelWin::ProcessMessageForDelivery(Message* message) {
// Sending a brokerable attachment requires a call to Channel::Send(), so
- // both Send() and ProcessMessageForDelivery() may be re-entrant. Brokered
- // attachments must be sent before the Message itself.
+ // both Send() and ProcessMessageForDelivery() may be re-entrant.
if (message->HasBrokerableAttachments()) {
DCHECK(GetAttachmentBroker());
DCHECK(peer_pid_ != base::kNullProcessId);
- for (const BrokerableAttachment* attachment :
- message->attachment_set()->PeekBrokerableAttachments()) {
+ for (const scoped_refptr<IPC::BrokerableAttachment>& attachment :
+ message->attachment_set()->GetBrokerableAttachments()) {
if (!GetAttachmentBroker()->SendAttachmentToProcess(attachment,
peer_pid_)) {
delete message;
@@ -161,7 +161,17 @@ void ChannelWin::FlushPrelimQueue() {
while (!prelim_queue.empty()) {
Message* m = prelim_queue.front();
- ProcessMessageForDelivery(m);
+ bool success = ProcessMessageForDelivery(m);
+ prelim_queue.pop();
+
+ if (!success)
+ break;
+ }
+
+ // Delete any unprocessed messages.
+ while (!prelim_queue.empty()) {
+ Message* m = prelim_queue.front();
+ delete m;
prelim_queue.pop();
}
}
@@ -254,9 +264,9 @@ void ChannelWin::HandleInternalMessage(const Message& msg) {
// Validation completed.
validate_client_ = false;
- FlushPrelimQueue();
-
listener()->OnChannelConnected(claimed_pid);
+
+ FlushPrelimQueue();
}
base::ProcessId ChannelWin::GetSenderPID() {
diff --git a/chromium/ipc/ipc_channel_win.h b/chromium/ipc/ipc_channel_win.h
index 35a158e3c6d..fd186fc186f 100644
--- a/chromium/ipc/ipc_channel_win.h
+++ b/chromium/ipc/ipc_channel_win.h
@@ -12,6 +12,7 @@
#include <queue>
#include <string>
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
diff --git a/chromium/ipc/ipc_fuzzing_tests.cc b/chromium/ipc/ipc_fuzzing_tests.cc
index 769922d036f..6eb93054c66 100644
--- a/chromium/ipc/ipc_fuzzing_tests.cc
+++ b/chromium/ipc/ipc_fuzzing_tests.cc
@@ -13,6 +13,7 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
#include "ipc/ipc_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -185,7 +186,7 @@ class FuzzerServerListener : public SimpleListener {
--message_count_;
--pending_messages_;
if (0 == message_count_)
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
void ReplyMsgNotHandled(uint32_t type_id) {
@@ -212,7 +213,7 @@ class FuzzerClientListener : public SimpleListener {
bool OnMessageReceived(const IPC::Message& msg) override {
last_msg_ = new IPC::Message(msg);
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
return true;
}
diff --git a/chromium/ipc/ipc_logging.cc b/chromium/ipc/ipc_logging.cc
index a9aa0060c08..abe26cb82d7 100644
--- a/chromium/ipc/ipc_logging.cc
+++ b/chromium/ipc/ipc_logging.cc
@@ -8,6 +8,9 @@
#define IPC_MESSAGE_MACROS_LOG_ENABLED
#endif
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
@@ -19,6 +22,7 @@
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_sender.h"
#include "ipc/ipc_switches.h"
diff --git a/chromium/ipc/ipc_message.cc b/chromium/ipc/ipc_message.cc
index df28464e234..71f72997452 100644
--- a/chromium/ipc/ipc_message.cc
+++ b/chromium/ipc/ipc_message.cc
@@ -5,10 +5,13 @@
#include "ipc/ipc_message.h"
#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
#include "base/atomic_sequence_num.h"
#include "base/logging.h"
#include "build/build_config.h"
+#include "ipc/attachment_broker.h"
#include "ipc/ipc_message_attachment.h"
#include "ipc/ipc_message_attachment_set.h"
#include "ipc/placeholder_brokerable_attachment.h"
@@ -49,7 +52,7 @@ Message::~Message() {
Message::Message() : base::Pickle(sizeof(Header)) {
header()->routing = header()->type = 0;
header()->flags = GetRefNumUpper24();
-#if defined(OS_MACOSX)
+#if USE_ATTACHMENT_BROKER
header()->num_brokered_attachments = 0;
#endif
#if defined(OS_POSIX)
@@ -65,7 +68,7 @@ Message::Message(int32_t routing_id, uint32_t type, PriorityValue priority)
header()->type = type;
DCHECK((priority & 0xffffff00) == 0);
header()->flags = priority | GetRefNumUpper24();
-#if defined(OS_MACOSX)
+#if USE_ATTACHMENT_BROKER
header()->num_brokered_attachments = 0;
#endif
#if defined(OS_POSIX)
@@ -83,6 +86,7 @@ Message::Message(const char* data, int data_len)
Message::Message(const Message& other) : base::Pickle(other) {
Init();
attachment_set_ = other.attachment_set_;
+ sender_pid_ = other.sender_pid_;
}
void Message::Init() {
@@ -98,6 +102,7 @@ void Message::Init() {
Message& Message::operator=(const Message& other) {
*static_cast<base::Pickle*>(this) = other;
attachment_set_ = other.attachment_set_;
+ sender_pid_ = other.sender_pid_;
return *this;
}
@@ -144,16 +149,15 @@ Message::NextMessageInfo::~NextMessageInfo() {}
Message::SerializedAttachmentIds
Message::SerializedIdsOfBrokerableAttachments() {
DCHECK(HasBrokerableAttachments());
- std::vector<const BrokerableAttachment*> attachments =
- attachment_set_->PeekBrokerableAttachments();
+ std::vector<scoped_refptr<IPC::BrokerableAttachment>> attachments(
+ attachment_set_->GetBrokerableAttachments());
CHECK_LE(attachments.size(), std::numeric_limits<size_t>::max() /
BrokerableAttachment::kNonceSize);
size_t size = attachments.size() * BrokerableAttachment::kNonceSize;
char* buffer = static_cast<char*>(malloc(size));
for (size_t i = 0; i < attachments.size(); ++i) {
- const BrokerableAttachment* attachment = attachments[i];
char* start_range = buffer + i * BrokerableAttachment::kNonceSize;
- BrokerableAttachment::AttachmentId id = attachment->GetIdentifier();
+ BrokerableAttachment::AttachmentId id = attachments[i]->GetIdentifier();
id.SerializeToBuffer(start_range, BrokerableAttachment::kNonceSize);
}
SerializedAttachmentIds ids;
@@ -204,7 +208,7 @@ void Message::FindNext(const char* range_start,
if (buffer_length < attachment_length + pickle_size)
return;
- for (int i = 0; i < num_attachments; ++i) {
+ for (size_t i = 0; i < num_attachments; ++i) {
const char* attachment_start =
pickle_end + i * BrokerableAttachment::kNonceSize;
BrokerableAttachment::AttachmentId id(attachment_start,
@@ -237,24 +241,46 @@ bool Message::AddPlaceholderBrokerableAttachmentWithId(
}
bool Message::WriteAttachment(scoped_refptr<MessageAttachment> attachment) {
- // We write the index of the descriptor so that we don't have to
+ bool brokerable;
+ size_t index;
+ bool success =
+ attachment_set()->AddAttachment(attachment, &index, &brokerable);
+ DCHECK(success);
+
+ // Write the type of descriptor.
+ WriteBool(brokerable);
+
+ // Write the index of the descriptor so that we don't have to
// keep the current descriptor as extra decoding state when deserialising.
- WriteInt(attachment_set()->size());
- return attachment_set()->AddAttachment(attachment);
+ WriteInt(static_cast<int>(index));
+
+#if USE_ATTACHMENT_BROKER
+ if (brokerable)
+ header()->num_brokered_attachments++;
+#endif
+
+ return success;
}
bool Message::ReadAttachment(
base::PickleIterator* iter,
scoped_refptr<MessageAttachment>* attachment) const {
- int descriptor_index;
- if (!iter->ReadInt(&descriptor_index))
+ bool brokerable;
+ if (!iter->ReadBool(&brokerable))
+ return false;
+
+ int index;
+ if (!iter->ReadInt(&index))
return false;
MessageAttachmentSet* attachment_set = attachment_set_.get();
if (!attachment_set)
return false;
- *attachment = attachment_set->GetAttachmentAt(descriptor_index);
+ *attachment = brokerable
+ ? attachment_set->GetBrokerableAttachmentAt(index)
+ : attachment_set->GetNonBrokerableAttachmentAt(index);
+
return nullptr != attachment->get();
}
diff --git a/chromium/ipc/ipc_message.h b/chromium/ipc/ipc_message.h
index 22d1c99da98..a6c641d7104 100644
--- a/chromium/ipc/ipc_message.h
+++ b/chromium/ipc/ipc_message.h
@@ -5,6 +5,7 @@
#ifndef IPC_IPC_MESSAGE_H_
#define IPC_IPC_MESSAGE_H_
+#include <stddef.h>
#include <stdint.h>
#include <string>
@@ -13,6 +14,8 @@
#include "base/memory/ref_counted.h"
#include "base/pickle.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
+#include "ipc/attachment_broker.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_export.h"
@@ -268,7 +271,7 @@ class IPC_EXPORT Message : public base::Pickle {
int32_t routing; // ID of the view that this message is destined for
uint32_t type; // specifies the user-defined message type
uint32_t flags; // specifies control flags for the message
-#if defined(OS_MACOSX)
+#if USE_ATTACHMENT_BROKER
// The number of brokered attachments included with this message. The
// ids of the brokered attachment ids are sent immediately after the pickled
// message, before the next pickled message is sent.
diff --git a/chromium/ipc/ipc_message_attachment.h b/chromium/ipc/ipc_message_attachment.h
index e7553d262cf..dda06300012 100644
--- a/chromium/ipc/ipc_message_attachment.h
+++ b/chromium/ipc/ipc_message_attachment.h
@@ -8,6 +8,7 @@
#include "base/files/file.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
#include "ipc/ipc_export.h"
namespace IPC {
@@ -15,7 +16,7 @@ namespace IPC {
// Auxiliary data sent with |Message|. This can be a platform file descriptor
// or a mojo |MessagePipe|. |GetType()| returns the type of the subclass.
class IPC_EXPORT MessageAttachment
- : public base::RefCounted<MessageAttachment> {
+ : public base::RefCountedThreadSafe<MessageAttachment> {
public:
enum Type {
TYPE_PLATFORM_FILE, // The instance is |PlatformFileAttachment|.
@@ -30,7 +31,7 @@ class IPC_EXPORT MessageAttachment
#endif // OS_POSIX
protected:
- friend class base::RefCounted<MessageAttachment>;
+ friend class base::RefCountedThreadSafe<MessageAttachment>;
MessageAttachment();
virtual ~MessageAttachment();
diff --git a/chromium/ipc/ipc_message_attachment_set.cc b/chromium/ipc/ipc_message_attachment_set.cc
index 6a8024fe9e6..3b7eefb9a6e 100644
--- a/chromium/ipc/ipc_message_attachment_set.cc
+++ b/chromium/ipc/ipc_message_attachment_set.cc
@@ -4,15 +4,19 @@
#include "ipc/ipc_message_attachment_set.h"
+#include <stddef.h>
+
#include <algorithm>
+
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_message_attachment.h"
#if defined(OS_POSIX)
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "ipc/ipc_platform_file_attachment_posix.h"
#endif // OS_POSIX
@@ -39,7 +43,7 @@ MessageAttachmentSet::MessageAttachmentSet()
}
MessageAttachmentSet::~MessageAttachmentSet() {
- if (consumed_descriptor_highwater_ == size())
+ if (consumed_descriptor_highwater_ == num_non_brokerable_attachments())
return;
// We close all the owning descriptors. If this message should have
@@ -51,7 +55,7 @@ MessageAttachmentSet::~MessageAttachmentSet() {
// 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();
+ << consumed_descriptor_highwater_ << "/" << num_descriptors();
}
unsigned MessageAttachmentSet::num_descriptors() const {
@@ -65,16 +69,22 @@ unsigned MessageAttachmentSet::num_mojo_handles() const {
}
unsigned MessageAttachmentSet::num_brokerable_attachments() const {
- return count_attachments_of_type(
- attachments_, MessageAttachment::TYPE_BROKERABLE_ATTACHMENT);
+ return static_cast<unsigned>(brokerable_attachments_.size());
}
-unsigned MessageAttachmentSet::size() const {
+unsigned MessageAttachmentSet::num_non_brokerable_attachments() const {
return static_cast<unsigned>(attachments_.size());
}
+unsigned MessageAttachmentSet::size() const {
+ return static_cast<unsigned>(attachments_.size() +
+ brokerable_attachments_.size());
+}
+
bool MessageAttachmentSet::AddAttachment(
- scoped_refptr<MessageAttachment> attachment) {
+ scoped_refptr<MessageAttachment> attachment,
+ size_t* index,
+ bool* brokerable) {
#if defined(OS_POSIX)
if (attachment->GetType() == MessageAttachment::TYPE_PLATFORM_FILE &&
num_descriptors() == kMaxDescriptorsPerMessage) {
@@ -83,14 +93,37 @@ bool MessageAttachmentSet::AddAttachment(
}
#endif
- attachments_.push_back(attachment);
- return true;
+ switch (attachment->GetType()) {
+ case MessageAttachment::TYPE_PLATFORM_FILE:
+ case MessageAttachment::TYPE_MOJO_HANDLE:
+ attachments_.push_back(attachment);
+ *index = attachments_.size() - 1;
+ *brokerable = false;
+ return true;
+ case MessageAttachment::TYPE_BROKERABLE_ATTACHMENT:
+ BrokerableAttachment* brokerable_attachment =
+ static_cast<BrokerableAttachment*>(attachment.get());
+ scoped_refptr<BrokerableAttachment> a(brokerable_attachment);
+ brokerable_attachments_.push_back(a);
+ *index = brokerable_attachments_.size() - 1;
+ *brokerable = true;
+ return true;
+ }
+ return false;
}
-scoped_refptr<MessageAttachment> MessageAttachmentSet::GetAttachmentAt(
- unsigned index) {
- if (index >= size()) {
- DLOG(WARNING) << "Accessing out of bound index:" << index << "/" << size();
+bool MessageAttachmentSet::AddAttachment(
+ scoped_refptr<MessageAttachment> attachment) {
+ bool brokerable;
+ size_t index;
+ return AddAttachment(attachment, &index, &brokerable);
+}
+
+scoped_refptr<MessageAttachment>
+MessageAttachmentSet::GetNonBrokerableAttachmentAt(unsigned index) {
+ if (index >= num_non_brokerable_attachments()) {
+ DLOG(WARNING) << "Accessing out of bound index:" << index << "/"
+ << num_non_brokerable_attachments();
return scoped_refptr<MessageAttachment>();
}
@@ -115,8 +148,10 @@ scoped_refptr<MessageAttachment> MessageAttachmentSet::GetAttachmentAt(
// 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())
+ if (index == 0 &&
+ consumed_descriptor_highwater_ == num_non_brokerable_attachments()) {
consumed_descriptor_highwater_ = 0;
+ }
if (index != consumed_descriptor_highwater_)
return scoped_refptr<MessageAttachment>();
@@ -126,34 +161,36 @@ scoped_refptr<MessageAttachment> MessageAttachmentSet::GetAttachmentAt(
return attachments_[index];
}
-void MessageAttachmentSet::CommitAll() {
+scoped_refptr<MessageAttachment>
+MessageAttachmentSet::GetBrokerableAttachmentAt(unsigned index) {
+ if (index >= num_brokerable_attachments()) {
+ DLOG(WARNING) << "Accessing out of bound index:" << index << "/"
+ << num_brokerable_attachments();
+ return scoped_refptr<MessageAttachment>();
+ }
+
+ scoped_refptr<BrokerableAttachment> brokerable_attachment(
+ brokerable_attachments_[index]);
+ return scoped_refptr<MessageAttachment>(brokerable_attachment.get());
+}
+
+void MessageAttachmentSet::CommitAllDescriptors() {
attachments_.clear();
consumed_descriptor_highwater_ = 0;
}
-std::vector<const BrokerableAttachment*>
-MessageAttachmentSet::PeekBrokerableAttachments() const {
- std::vector<const BrokerableAttachment*> output;
- for (const scoped_refptr<MessageAttachment>& attachment : attachments_) {
- if (attachment->GetType() ==
- MessageAttachment::TYPE_BROKERABLE_ATTACHMENT) {
- output.push_back(static_cast<BrokerableAttachment*>(attachment.get()));
- }
- }
- return output;
+std::vector<scoped_refptr<IPC::BrokerableAttachment>>
+MessageAttachmentSet::GetBrokerableAttachments() const {
+ return brokerable_attachments_;
}
void MessageAttachmentSet::ReplacePlaceholderWithAttachment(
const scoped_refptr<BrokerableAttachment>& attachment) {
- for (auto it = attachments_.begin(); it != attachments_.end(); ++it) {
- if ((*it)->GetType() != MessageAttachment::TYPE_BROKERABLE_ATTACHMENT)
- continue;
- BrokerableAttachment* brokerable_attachment =
- static_cast<BrokerableAttachment*>(it->get());
-
- if (brokerable_attachment->GetBrokerableType() ==
- BrokerableAttachment::PLACEHOLDER &&
- brokerable_attachment->GetIdentifier() == attachment->GetIdentifier()) {
+ DCHECK_NE(BrokerableAttachment::PLACEHOLDER, attachment->GetBrokerableType());
+ for (auto it = brokerable_attachments_.begin();
+ it != brokerable_attachments_.end(); ++it) {
+ if ((*it)->GetBrokerableType() == BrokerableAttachment::PLACEHOLDER &&
+ (*it)->GetIdentifier() == attachment->GetIdentifier()) {
*it = attachment;
return;
}
@@ -191,7 +228,7 @@ void MessageAttachmentSet::ReleaseFDsToClose(
fds->push_back(file->TakePlatformFile());
}
- CommitAll();
+ CommitAllDescriptors();
}
void MessageAttachmentSet::AddDescriptorsToOwn(const base::PlatformFile* buffer,
diff --git a/chromium/ipc/ipc_message_attachment_set.h b/chromium/ipc/ipc_message_attachment_set.h
index 4707a504e3c..764c818c9f0 100644
--- a/chromium/ipc/ipc_message_attachment_set.h
+++ b/chromium/ipc/ipc_message_attachment_set.h
@@ -5,10 +5,13 @@
#ifndef IPC_IPC_MESSAGE_ATTACHMENT_SET_H_
#define IPC_IPC_MESSAGE_ATTACHMENT_SET_H_
+#include <stddef.h>
+
#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
#include "ipc/ipc_export.h"
#if defined(OS_POSIX)
@@ -21,10 +24,21 @@ class BrokerableAttachment;
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).
+// A MessageAttachmentSet is an ordered set of MessageAttachment objects
+// associated with an IPC message. There are three types of MessageAttachments:
+// 1) TYPE_PLATFORM_FILE is transmitted over the Channel's underlying
+// UNIX domain socket
+// 2) TYPE_MOJO_HANDLE is transmitted over the Mojo MessagePipe.
+// 3) TYPE_BROKERABLE_ATTACHMENT is transmitted by the Attachment Broker.
+// Any given IPC Message can have attachments of type (1) or (2), but not both.
+// These are stored in |attachments_|. Attachments of type (3) are stored in
+// |brokerable_attachments_|.
+//
+// To produce a deterministic ordering, all attachments in |attachments_| are
+// considered to come before those in |brokerable_attachments_|. These
+// attachments are transmitted across different communication channels, and
+// multiplexed by the receiver, so ordering between them cannot be guaranteed.
+//
// -----------------------------------------------------------------------------
class IPC_EXPORT MessageAttachmentSet
: public base::RefCountedThreadSafe<MessageAttachmentSet> {
@@ -39,27 +53,45 @@ class IPC_EXPORT MessageAttachmentSet
unsigned num_mojo_handles() const;
// Return the number of brokerable attachments in the attachment set.
unsigned num_brokerable_attachments() const;
+ // Return the number of non-brokerable attachments in the attachment set.
+ unsigned num_non_brokerable_attachments() const;
// Return true if no unconsumed descriptors remain
bool empty() const { return 0 == size(); }
+ // Returns whether the attachment was successfully added.
+ // |index| is an output variable. On success, it contains the index of the
+ // newly added attachment.
+ // |brokerable| is an output variable. On success, it describes which vector
+ // the attachment was added to.
+ bool AddAttachment(scoped_refptr<MessageAttachment> attachment,
+ size_t* index,
+ bool* brokerable);
+
+ // Similar to the above method, but without output variables.
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.
+ // Take the nth non-brokerable attachment from the beginning of the vector,
+ // 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: an attachment, or nullptr on error
- scoped_refptr<MessageAttachment> GetAttachmentAt(unsigned index);
+ scoped_refptr<MessageAttachment> GetNonBrokerableAttachmentAt(unsigned index);
+
+ // Similar to GetNonBrokerableAttachmentAt, but there are no ordering
+ // requirements.
+ scoped_refptr<MessageAttachment> GetBrokerableAttachmentAt(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();
+ // PeekDescriptors. It marks all the non-brokerable descriptors as consumed
+ // and closes those which are auto-close.
+ void CommitAllDescriptors();
// Returns a vector of all brokerable attachments.
- std::vector<const BrokerableAttachment*> PeekBrokerableAttachments() const;
+ std::vector<scoped_refptr<IPC::BrokerableAttachment>>
+ GetBrokerableAttachments() const;
// Replaces a placeholder brokerable attachment with |attachment|, matching
// them by their id.
@@ -80,15 +112,16 @@ class IPC_EXPORT MessageAttachmentSet
// ---------------------------------------------------------------------------
// Interfaces for transmission...
- // Fill an array with file descriptors without 'consuming' them. CommitAll
- // must be called after these descriptors have been transmitted.
+ // Fill an array with file descriptors without 'consuming' them.
+ // CommitAllDescriptors must be called after these descriptors have been
+ // transmitted.
// buffer: (output) a buffer of, at least, size() integers.
void PeekDescriptors(base::PlatformFile* buffer) const;
// Returns true if any contained file descriptors appear to be handles to a
// directory.
bool ContainsDirectoryDescriptor() const;
- // Fetch all filedescriptors with the "auto close" property.
- // Used instead of CommitAll() when closing must be handled manually.
+ // Fetch all filedescriptors with the "auto close" property. Used instead of
+ // CommitAllDescriptors() when closing must be handled manually.
void ReleaseFDsToClose(std::vector<base::PlatformFile>* fds);
// ---------------------------------------------------------------------------
@@ -110,10 +143,12 @@ class IPC_EXPORT MessageAttachmentSet
~MessageAttachmentSet();
- // A vector of attachments of the message, which might be |PlatformFile| or
- // |MessagePipe|.
+ // All elements either have type TYPE_PLATFORM_FILE or TYPE_MOJO_HANDLE.
std::vector<scoped_refptr<MessageAttachment>> attachments_;
+ // All elements have type TYPE_BROKERABLE_ATTACHMENT.
+ std::vector<scoped_refptr<BrokerableAttachment>> brokerable_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
// all the descriptors have been read (with GetNthDescriptor). Secondly, we
diff --git a/chromium/ipc/ipc_message_attachment_set_posix_unittest.cc b/chromium/ipc/ipc_message_attachment_set_posix_unittest.cc
index 8df312f1d37..e43e43163cb 100644
--- a/chromium/ipc/ipc_message_attachment_set_posix_unittest.cc
+++ b/chromium/ipc/ipc_message_attachment_set_posix_unittest.cc
@@ -7,9 +7,11 @@
#include "ipc/ipc_message_attachment_set.h"
#include <fcntl.h>
+#include <stddef.h>
#include <unistd.h>
#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
#include "ipc/ipc_platform_file_attachment_posix.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -49,7 +51,7 @@ TEST(MessageAttachmentSet, BasicAdd) {
// Empties the set and stops a warning about deleting a set with unconsumed
// descriptors
- set->CommitAll();
+ set->CommitAllDescriptors();
}
TEST(MessageAttachmentSet, BasicAddAndClose) {
@@ -63,7 +65,7 @@ TEST(MessageAttachmentSet, BasicAddAndClose) {
ASSERT_EQ(set->size(), 1u);
ASSERT_TRUE(!set->empty());
- set->CommitAll();
+ set->CommitAllDescriptors();
ASSERT_TRUE(VerifyClosed(fd));
}
@@ -77,7 +79,7 @@ TEST(MessageAttachmentSet, MaxSize) {
ASSERT_TRUE(
!set->AddAttachment(new internal::PlatformFileAttachment(kFDBase)));
- set->CommitAll();
+ set->CommitAllDescriptors();
}
#if defined(OS_ANDROID)
@@ -98,7 +100,7 @@ TEST(MessageAttachmentSet, MAYBE_SetDescriptors) {
ASSERT_TRUE(!set->empty());
ASSERT_EQ(set->size(), 1u);
- set->CommitAll();
+ set->CommitAllDescriptors();
ASSERT_TRUE(VerifyClosed(fd));
}
@@ -114,7 +116,7 @@ TEST(MessageAttachmentSet, PeekDescriptors) {
fds[0] = 0;
set->PeekDescriptors(fds);
ASSERT_EQ(fds[0], kFDBase);
- set->CommitAll();
+ set->CommitAllDescriptors();
ASSERT_TRUE(set->empty());
}
@@ -130,11 +132,13 @@ TEST(MessageAttachmentSet, WalkInOrder) {
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->GetNonBrokerableAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(1)->TakePlatformFile(),
+ kFDBase + 1);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(2)->TakePlatformFile(),
+ kFDBase + 2);
- set->CommitAll();
+ set->CommitAllDescriptors();
}
TEST(MessageAttachmentSet, WalkWrongOrder) {
@@ -149,10 +153,10 @@ TEST(MessageAttachmentSet, WalkWrongOrder) {
ASSERT_TRUE(
set->AddAttachment(new internal::PlatformFileAttachment(kFDBase + 2)));
- ASSERT_EQ(set->GetAttachmentAt(0)->TakePlatformFile(), kFDBase);
- ASSERT_EQ(set->GetAttachmentAt(2), nullptr);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(2), nullptr);
- set->CommitAll();
+ set->CommitAllDescriptors();
}
TEST(MessageAttachmentSet, WalkCycle) {
@@ -167,17 +171,23 @@ TEST(MessageAttachmentSet, WalkCycle) {
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();
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(1)->TakePlatformFile(),
+ kFDBase + 1);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(2)->TakePlatformFile(),
+ kFDBase + 2);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(1)->TakePlatformFile(),
+ kFDBase + 1);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(2)->TakePlatformFile(),
+ kFDBase + 2);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(0)->TakePlatformFile(), kFDBase);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(1)->TakePlatformFile(),
+ kFDBase + 1);
+ ASSERT_EQ(set->GetNonBrokerableAttachmentAt(2)->TakePlatformFile(),
+ kFDBase + 2);
+
+ set->CommitAllDescriptors();
}
#if defined(OS_ANDROID)
@@ -190,7 +200,7 @@ TEST(MessageAttachmentSet, MAYBE_DontClose) {
const int fd = GetSafeFd();
ASSERT_TRUE(set->AddAttachment(new internal::PlatformFileAttachment(fd)));
- set->CommitAll();
+ set->CommitAllDescriptors();
ASSERT_FALSE(VerifyClosed(fd));
}
@@ -201,7 +211,7 @@ TEST(MessageAttachmentSet, DoClose) {
const int fd = GetSafeFd();
ASSERT_TRUE(set->AddAttachment(
new internal::PlatformFileAttachment(base::ScopedFD(fd))));
- set->CommitAll();
+ set->CommitAllDescriptors();
ASSERT_TRUE(VerifyClosed(fd));
}
diff --git a/chromium/ipc/ipc_message_macros.h b/chromium/ipc/ipc_message_macros.h
index daeb617c452..f9fc28e6c94 100644
--- a/chromium/ipc/ipc_message_macros.h
+++ b/chromium/ipc/ipc_message_macros.h
@@ -444,7 +444,7 @@
Method func) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- DispatchToMethod(obj, func, p); \
+ base::DispatchToMethod(obj, func, p); \
return true; \
} \
return false; \
diff --git a/chromium/ipc/ipc_message_start.h b/chromium/ipc/ipc_message_start.h
index 26ce0451fb3..8197ac62970 100644
--- a/chromium/ipc/ipc_message_start.h
+++ b/chromium/ipc/ipc_message_start.h
@@ -79,7 +79,6 @@ enum IPCMessageStart {
WebSocketMsgStart,
NaClHostMsgStart,
WebRTCIdentityMsgStart,
- LocalDiscoveryMsgStart,
PowerMonitorMsgStart,
EncryptedMediaMsgStart,
CacheStorageMsgStart,
@@ -113,6 +112,7 @@ enum IPCMessageStart {
BluetoothMsgStart,
CastMediaMsgStart,
AwMessagePortMsgStart,
+ SyncCompositorMsgStart,
ExtensionsGuestViewMsgStart,
GuestViewMsgStart,
// Note: CastCryptoMsgStart and CastChannelMsgStart reserved for Chromecast
@@ -127,7 +127,14 @@ enum IPCMessageStart {
RenderProcessMsgStart,
PageLoadMetricsMsgStart,
MemoryMsgStart,
+ MediaSessionMsgStart,
IPCTestMsgStart,
+ ArcInstanceMsgStart,
+ ArcInstanceHostMsgStart,
+ DistillerMsgStart,
+ StartupMetricMsgStart,
+ ArcCameraMsgStart,
+ DWriteFontProxyMsgStart,
LastIPCMsgStart // Must come last.
};
diff --git a/chromium/ipc/ipc_message_unittest.cc b/chromium/ipc/ipc_message_unittest.cc
index a4f9af07244..c022f9765a8 100644
--- a/chromium/ipc/ipc_message_unittest.cc
+++ b/chromium/ipc/ipc_message_unittest.cc
@@ -4,6 +4,8 @@
#include "ipc/ipc_message.h"
+#include <stddef.h>
+#include <stdint.h>
#include <string.h>
#include <limits>
@@ -11,6 +13,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "build/build_config.h"
+#include "ipc/attachment_broker.h"
#include "ipc/ipc_message_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/ipc/ipc_message_utils.cc b/chromium/ipc/ipc_message_utils.cc
index 3baf2ee8a52..ea88b55a2a5 100644
--- a/chromium/ipc/ipc_message_utils.cc
+++ b/chromium/ipc/ipc_message_utils.cc
@@ -4,6 +4,9 @@
#include "ipc/ipc_message_utils.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/files/file_path.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h"
@@ -12,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_attachment.h"
#include "ipc/ipc_message_attachment_set.h"
@@ -24,6 +28,10 @@
#include "base/memory/shared_memory_handle.h"
#endif // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "ipc/mach_port_mac.h"
+#endif
+
#if defined(OS_WIN)
#include <tchar.h>
#include "ipc/handle_win.h"
@@ -270,6 +278,24 @@ void ParamTraits<bool>::Log(const param_type& p, std::string* l) {
l->append(p ? "true" : "false");
}
+void ParamTraits<signed char>::Write(Message* m, const param_type& p) {
+ m->WriteBytes(&p, sizeof(param_type));
+}
+
+bool ParamTraits<signed char>::Read(const Message* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ const char* data;
+ if (!iter->ReadBytes(&data, sizeof(param_type)))
+ return false;
+ memcpy(r, data, sizeof(param_type));
+ return true;
+}
+
+void ParamTraits<signed char>::Log(const param_type& p, std::string* l) {
+ l->append(base::IntToString(p));
+}
+
void ParamTraits<unsigned char>::Write(Message* m, const param_type& p) {
m->WriteBytes(&p, sizeof(param_type));
}
@@ -553,7 +579,18 @@ void ParamTraits<base::SharedMemoryHandle>::Write(Message* m,
ParamTraits<base::FileDescriptor>::Write(m, p.GetFileDescriptor());
break;
case base::SharedMemoryHandle::MACH:
- // TODO(erikchen): Implement me. http://crbug.com/535711
+ MachPortMac mach_port_mac(p.GetMemoryObject());
+ ParamTraits<MachPortMac>::Write(m, mach_port_mac);
+ size_t size = 0;
+ bool result = p.GetSize(&size);
+ DCHECK(result);
+ ParamTraits<size_t>::Write(m, size);
+
+ // If the caller intended to pass ownership to the IPC stack, release a
+ // reference.
+ if (p.OwnershipPassesToIPC())
+ p.Close();
+
break;
}
}
@@ -591,7 +628,16 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const Message* m,
return true;
}
case base::SharedMemoryHandle::MACH: {
- // TODO(erikchen): Implement me. http://crbug.com/535711
+ MachPortMac mach_port_mac;
+ if (!ParamTraits<MachPortMac>::Read(m, iter, &mach_port_mac))
+ return false;
+
+ size_t size;
+ if (!ParamTraits<size_t>::Read(m, iter, &size))
+ return false;
+
+ *r = base::SharedMemoryHandle(mach_port_mac.get_mach_port(), size,
+ base::GetCurrentProcId());
return true;
}
}
@@ -605,7 +651,8 @@ void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p,
ParamTraits<base::FileDescriptor>::Log(p.GetFileDescriptor(), l);
break;
case base::SharedMemoryHandle::MACH:
- // TODO(erikchen): Implement me. http://crbug.com/535711
+ l->append("Mach port: ");
+ LogParam(p.GetMemoryObject(), l);
break;
}
}
@@ -613,9 +660,6 @@ void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p,
#elif defined(OS_WIN)
void ParamTraits<base::SharedMemoryHandle>::Write(Message* m,
const param_type& p) {
- // Longs on windows are 32 bits.
- uint32_t pid = p.GetPID();
- m->WriteUInt32(pid);
m->WriteBool(p.NeedsBrokering());
if (p.NeedsBrokering()) {
@@ -629,11 +673,6 @@ void ParamTraits<base::SharedMemoryHandle>::Write(Message* m,
bool ParamTraits<base::SharedMemoryHandle>::Read(const Message* m,
base::PickleIterator* iter,
param_type* r) {
- uint32_t pid_int;
- if (!iter->ReadUInt32(&pid_int))
- return false;
- base::ProcessId pid = pid_int;
-
bool needs_brokering;
if (!iter->ReadBool(&needs_brokering))
return false;
@@ -642,7 +681,8 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const Message* m,
HandleWin handle_win;
if (!ParamTraits<HandleWin>::Read(m, iter, &handle_win))
return false;
- *r = base::SharedMemoryHandle(handle_win.get_handle(), pid);
+ *r = base::SharedMemoryHandle(handle_win.get_handle(),
+ base::GetCurrentProcId());
return true;
}
@@ -650,14 +690,12 @@ bool ParamTraits<base::SharedMemoryHandle>::Read(const Message* m,
if (!iter->ReadInt(&handle_int))
return false;
HANDLE handle = LongToHandle(handle_int);
- *r = base::SharedMemoryHandle(handle, pid);
+ *r = base::SharedMemoryHandle(handle, base::GetCurrentProcId());
return true;
}
void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p,
std::string* l) {
- LogParam(p.GetPID(), l);
- l->append(" ");
LogParam(p.GetHandle(), l);
l->append(" needs brokering: ");
LogParam(p.NeedsBrokering(), l);
@@ -822,25 +860,6 @@ void ParamTraits<base::TimeTicks>::Log(const param_type& p, std::string* l) {
ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
}
-void ParamTraits<base::TraceTicks>::Write(Message* m, const param_type& p) {
- ParamTraits<int64_t>::Write(m, p.ToInternalValue());
-}
-
-bool ParamTraits<base::TraceTicks>::Read(const Message* m,
- base::PickleIterator* iter,
- param_type* r) {
- int64_t value;
- bool ret = ParamTraits<int64_t>::Read(m, iter, &value);
- if (ret)
- *r = base::TraceTicks::FromInternalValue(value);
-
- return ret;
-}
-
-void ParamTraits<base::TraceTicks>::Log(const param_type& p, std::string* l) {
- ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
-}
-
void ParamTraits<IPC::ChannelHandle>::Write(Message* m, const param_type& p) {
#if defined(OS_WIN)
// On Windows marshalling pipe handle is not supported.
@@ -966,7 +985,7 @@ bool ParamTraits<HANDLE>::Read(const Message* m,
}
void ParamTraits<HANDLE>::Log(const param_type& p, std::string* l) {
- l->append(base::StringPrintf("0x%X", p));
+ l->append(base::StringPrintf("0x%p", p));
}
void ParamTraits<LOGFONT>::Write(Message* m, const param_type& p) {
diff --git a/chromium/ipc/ipc_message_utils.h b/chromium/ipc/ipc_message_utils.h
index 45f424d7633..69ea7cb6d8a 100644
--- a/chromium/ipc/ipc_message_utils.h
+++ b/chromium/ipc/ipc_message_utils.h
@@ -5,6 +5,8 @@
#ifndef IPC_IPC_MESSAGE_UTILS_H_
#define IPC_IPC_MESSAGE_UTILS_H_
+#include <limits.h>
+#include <stddef.h>
#include <stdint.h>
#include <algorithm>
@@ -23,6 +25,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/tuple.h"
+#include "build/build_config.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_message_start.h"
#include "ipc/ipc_param_traits.h"
@@ -59,7 +62,6 @@ class NullableString16;
class Time;
class TimeDelta;
class TimeTicks;
-class TraceTicks;
struct FileDescriptor;
#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
@@ -133,6 +135,14 @@ struct ParamTraits<bool> {
};
template <>
+struct IPC_EXPORT ParamTraits<signed char> {
+ typedef signed char param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, base::PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
struct IPC_EXPORT ParamTraits<unsigned char> {
typedef unsigned char param_type;
static void Write(Message* m, const param_type& p);
@@ -577,16 +587,6 @@ struct IPC_EXPORT ParamTraits<base::TimeTicks> {
};
template <>
-struct IPC_EXPORT ParamTraits<base::TraceTicks> {
- typedef base::TraceTicks param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m,
- base::PickleIterator* iter,
- param_type* r);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
struct ParamTraits<base::Tuple<>> {
typedef base::Tuple<> param_type;
static void Write(Message* m, const param_type& p) {
@@ -1026,7 +1026,7 @@ class SyncMessageSchema {
Message* reply = SyncMessage::GenerateReply(msg);
if (ok) {
typename base::TupleTypes<ReplyParam>::ValueTuple reply_params;
- DispatchToMethod(obj, func, send_params, &reply_params);
+ base::DispatchToMethod(obj, func, send_params, &reply_params);
WriteParam(reply, reply_params);
LogReplyParamsToMessage(reply_params, msg);
} else {
@@ -1046,7 +1046,7 @@ class SyncMessageSchema {
if (ok) {
base::Tuple<Message&> t = base::MakeRefTuple(*reply);
ConnectMessageAndReply(msg, reply);
- DispatchToMethod(obj, func, send_params, &t);
+ base::DispatchToMethod(obj, func, send_params, &t);
} else {
NOTREACHED() << "Error deserializing message " << msg->type();
reply->set_reply_error();
diff --git a/chromium/ipc/ipc_message_utils_unittest.cc b/chromium/ipc/ipc_message_utils_unittest.cc
index 35a3e66271d..f3aa31a5160 100644
--- a/chromium/ipc/ipc_message_utils_unittest.cc
+++ b/chromium/ipc/ipc_message_utils_unittest.cc
@@ -4,6 +4,7 @@
#include "ipc/ipc_message_utils.h"
+#include <stddef.h>
#include <stdint.h>
#include "base/files/file_path.h"
diff --git a/chromium/ipc/ipc_perftest_support.cc b/chromium/ipc/ipc_perftest_support.cc
index 3af0a1fa948..1ecc7c740e3 100644
--- a/chromium/ipc/ipc_perftest_support.cc
+++ b/chromium/ipc/ipc_perftest_support.cc
@@ -4,6 +4,9 @@
#include "ipc/ipc_perftest_support.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <algorithm>
#include <string>
@@ -348,7 +351,7 @@ scoped_refptr<base::TaskRunner> PingPongTestClient::task_runner() {
LockThreadAffinity::LockThreadAffinity(int cpu_number)
: affinity_set_ok_(false) {
#if defined(OS_WIN)
- const DWORD_PTR thread_mask = 1 << cpu_number;
+ const DWORD_PTR thread_mask = static_cast<DWORD_PTR>(1) << cpu_number;
old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask);
affinity_set_ok_ = old_affinity_ != 0;
#elif defined(OS_LINUX)
diff --git a/chromium/ipc/ipc_perftest_support.h b/chromium/ipc/ipc_perftest_support.h
index 578256f8b11..80c58d127b9 100644
--- a/chromium/ipc/ipc_perftest_support.h
+++ b/chromium/ipc/ipc_perftest_support.h
@@ -5,8 +5,12 @@
#ifndef IPC_IPC_PERFTEST_SUPPORT_H_
#define IPC_IPC_PERFTEST_SUPPORT_H_
+#include <stddef.h>
+
#include <vector>
+#include "base/macros.h"
+#include "build/build_config.h"
#include "ipc/ipc_test_base.h"
namespace IPC {
diff --git a/chromium/ipc/ipc_platform_file.cc b/chromium/ipc/ipc_platform_file.cc
index 826d03014ed..97c176f3d7b 100644
--- a/chromium/ipc/ipc_platform_file.cc
+++ b/chromium/ipc/ipc_platform_file.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "build/build_config.h"
#include "ipc/ipc_platform_file.h"
#if defined(OS_POSIX)
diff --git a/chromium/ipc/ipc_platform_file.h b/chromium/ipc/ipc_platform_file.h
index df6e8e394c0..fb4d0e423de 100644
--- a/chromium/ipc/ipc_platform_file.h
+++ b/chromium/ipc/ipc_platform_file.h
@@ -7,6 +7,7 @@
#include "base/files/file.h"
#include "base/process/process.h"
+#include "build/build_config.h"
#include "ipc/ipc_export.h"
#if defined(OS_POSIX)
diff --git a/chromium/ipc/ipc_platform_file_attachment_posix.cc b/chromium/ipc/ipc_platform_file_attachment_posix.cc
index b704750c156..b130ab26eb7 100644
--- a/chromium/ipc/ipc_platform_file_attachment_posix.cc
+++ b/chromium/ipc/ipc_platform_file_attachment_posix.cc
@@ -4,6 +4,8 @@
#include "ipc/ipc_platform_file_attachment_posix.h"
+#include <utility>
+
namespace IPC {
namespace internal {
@@ -12,8 +14,7 @@ PlatformFileAttachment::PlatformFileAttachment(base::PlatformFile file)
}
PlatformFileAttachment::PlatformFileAttachment(base::ScopedFD file)
- : file_(file.get()), owning_(file.Pass()) {
-}
+ : file_(file.get()), owning_(std::move(file)) {}
PlatformFileAttachment::~PlatformFileAttachment() {
}
diff --git a/chromium/ipc/ipc_send_fds_test.cc b/chromium/ipc/ipc_send_fds_test.cc
index 22965da2d23..81f589412d6 100644
--- a/chromium/ipc/ipc_send_fds_test.cc
+++ b/chromium/ipc/ipc_send_fds_test.cc
@@ -11,6 +11,7 @@ extern "C" {
}
#endif
#include <fcntl.h>
+#include <stddef.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -73,7 +74,7 @@ class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase {
}
void OnChannelError() override {
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
protected:
@@ -96,7 +97,7 @@ class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase {
++num_fds_received_;
if (num_fds_received_ == kNumFDsToSend * kNumMessages)
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
private:
diff --git a/chromium/ipc/ipc_sync_channel.cc b/chromium/ipc/ipc_sync_channel.cc
index 89dd7d7113e..d1942112d9a 100644
--- a/chromium/ipc/ipc_sync_channel.cc
+++ b/chromium/ipc/ipc_sync_channel.cc
@@ -4,6 +4,10 @@
#include "ipc/ipc_sync_channel.h"
+#include <stddef.h>
+#include <stdint.h>
+#include <utility>
+
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/location.h"
@@ -305,15 +309,13 @@ bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) {
return false;
}
- // TODO(bauerb): Remove logging once investigation of http://crbug.com/141055
- // has finished.
if (!msg->is_reply_error()) {
bool send_result = deserializers_.back().deserializer->
SerializeOutputParameters(*msg);
deserializers_.back().send_result = send_result;
- VLOG_IF(1, !send_result) << "Couldn't deserialize reply message";
+ DVLOG_IF(1, !send_result) << "Couldn't deserialize reply message";
} else {
- VLOG(1) << "Received error reply";
+ DVLOG(1) << "Received error reply";
}
deserializers_.back().done_event->Signal();
@@ -370,7 +372,7 @@ void SyncChannel::SyncContext::OnChannelClosed() {
void SyncChannel::SyncContext::OnSendTimeout(int message_id) {
base::AutoLock auto_lock(deserializers_lock_);
PendingSyncMessageQueue::iterator iter;
- VLOG(1) << "Send timeout";
+ DVLOG(1) << "Send timeout";
for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
if (iter->id == message_id) {
iter->done_event->Signal();
@@ -382,8 +384,7 @@ void SyncChannel::SyncContext::OnSendTimeout(int message_id) {
void SyncChannel::SyncContext::CancelPendingSends() {
base::AutoLock auto_lock(deserializers_lock_);
PendingSyncMessageQueue::iterator iter;
- // TODO(bauerb): Remove once http://crbug/141055 is fixed.
- VLOG(1) << "Canceling pending sends";
+ DVLOG(1) << "Canceling pending sends";
for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++)
iter->done_event->Signal();
}
@@ -416,7 +417,7 @@ scoped_ptr<SyncChannel> SyncChannel::Create(
scoped_ptr<SyncChannel> channel =
Create(listener, ipc_task_runner, shutdown_event);
channel->Init(channel_handle, mode, create_pipe_now);
- return channel.Pass();
+ return channel;
}
// static
@@ -428,8 +429,8 @@ scoped_ptr<SyncChannel> SyncChannel::Create(
base::WaitableEvent* shutdown_event) {
scoped_ptr<SyncChannel> channel =
Create(listener, ipc_task_runner, shutdown_event);
- channel->Init(factory.Pass(), create_pipe_now);
- return channel.Pass();
+ channel->Init(std::move(factory), create_pipe_now);
+ return channel;
}
// static
@@ -487,7 +488,7 @@ bool SyncChannel::Send(Message* message) {
// *this* might get deleted in WaitForReply.
scoped_refptr<SyncContext> context(sync_context());
if (context->shutdown_event()->IsSignaled()) {
- VLOG(1) << "shutdown event is signaled";
+ DVLOG(1) << "shutdown event is signaled";
delete message;
return false;
}
diff --git a/chromium/ipc/ipc_sync_channel_unittest.cc b/chromium/ipc/ipc_sync_channel_unittest.cc
index a0968c7a051..21ebafb638c 100644
--- a/chromium/ipc/ipc_sync_channel_unittest.cc
+++ b/chromium/ipc/ipc_sync_channel_unittest.cc
@@ -4,6 +4,8 @@
#include "ipc/ipc_sync_channel.h"
+#include <stddef.h>
+
#include <string>
#include <vector>
@@ -20,6 +22,7 @@
#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_sender.h"
diff --git a/chromium/ipc/ipc_sync_message.cc b/chromium/ipc/ipc_sync_message.cc
index 8a770b17a1f..884dd8029d5 100644
--- a/chromium/ipc/ipc_sync_message.cc
+++ b/chromium/ipc/ipc_sync_message.cc
@@ -4,6 +4,8 @@
#include "ipc/ipc_sync_message.h"
+#include <stdint.h>
+
#include <stack>
#include "base/atomic_sequence_num.h"
diff --git a/chromium/ipc/ipc_sync_message.h b/chromium/ipc/ipc_sync_message.h
index 904a9c8505c..6dd3b632451 100644
--- a/chromium/ipc/ipc_sync_message.h
+++ b/chromium/ipc/ipc_sync_message.h
@@ -13,6 +13,7 @@
#include <string>
#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
#include "ipc/ipc_message.h"
namespace base {
diff --git a/chromium/ipc/ipc_test_base.cc b/chromium/ipc/ipc_test_base.cc
index f700856f244..6243138cd4b 100644
--- a/chromium/ipc/ipc_test_base.cc
+++ b/chromium/ipc/ipc_test_base.cc
@@ -2,15 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "build/build_config.h"
-
-#include "base/single_thread_task_runner.h"
#include "ipc/ipc_test_base.h"
+#include <utility>
+
#include "base/command_line.h"
#include "base/process/kill.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "ipc/ipc_descriptors.h"
#if defined(OS_POSIX)
@@ -48,7 +49,7 @@ void IPCTestBase::InitWithCustomMessageLoop(
DCHECK(!message_loop_);
test_client_name_ = test_client_name;
- message_loop_ = message_loop.Pass();
+ message_loop_ = std::move(message_loop);
}
void IPCTestBase::CreateChannel(IPC::Listener* listener) {
@@ -61,11 +62,11 @@ bool IPCTestBase::ConnectChannel() {
}
scoped_ptr<IPC::Channel> IPCTestBase::ReleaseChannel() {
- return channel_.Pass();
+ return std::move(channel_);
}
void IPCTestBase::SetChannel(scoped_ptr<IPC::Channel> channel) {
- channel_ = channel.Pass();
+ channel_ = std::move(channel);
}
diff --git a/chromium/ipc/ipc_test_base.h b/chromium/ipc/ipc_test_base.h
index 59f5b865403..360188f6a5b 100644
--- a/chromium/ipc/ipc_test_base.h
+++ b/chromium/ipc/ipc_test_base.h
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
#include "base/test/multiprocess_test.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_channel_factory.h"
#include "ipc/ipc_channel_proxy.h"
@@ -103,9 +104,6 @@ class IPCTestBase : public base::MultiProcessTest {
IPC::Channel* channel() { return channel_.get(); }
IPC::ChannelProxy* channel_proxy() { return channel_proxy_.get(); }
- void set_attachment_broker(IPC::AttachmentBroker* broker) {
- attachment_broker_ = broker;
- }
const base::Process& client_process() const { return client_process_; }
scoped_refptr<base::SequencedTaskRunner> task_runner();
@@ -124,10 +122,6 @@ class IPCTestBase : public base::MultiProcessTest {
scoped_ptr<IPC::Channel> channel_;
scoped_ptr<IPC::ChannelProxy> channel_proxy_;
- // The AttachmentBroker that should be passed to |channel_| when it is
- // created.
- IPC::AttachmentBroker* attachment_broker_;
-
base::Process client_process_;
DISALLOW_COPY_AND_ASSIGN(IPCTestBase);
diff --git a/chromium/ipc/ipc_test_channel_listener.cc b/chromium/ipc/ipc_test_channel_listener.cc
index 7d1832dd43b..4d25ca3b903 100644
--- a/chromium/ipc/ipc_test_channel_listener.cc
+++ b/chromium/ipc/ipc_test_channel_listener.cc
@@ -49,12 +49,12 @@ bool TestChannelListener::OnMessageReceived(const IPC::Message& message) {
void TestChannelListener::OnChannelError() {
// There is a race when closing the channel so the last message may be lost.
EXPECT_LE(messages_left_, 1);
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
void TestChannelListener::SendNextMessage() {
if (--messages_left_ <= 0)
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
else
SendOneMessage(sender_, "Foo");
}
diff --git a/chromium/ipc/ipc_test_messages.h b/chromium/ipc/ipc_test_messages.h
index 4bf927eb054..a61d1b013d2 100644
--- a/chromium/ipc/ipc_test_messages.h
+++ b/chromium/ipc/ipc_test_messages.h
@@ -2,13 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Multiply-included file, no traditional include guard.
#include "build/build_config.h"
-#if defined(OS_WIN)
-#include "ipc/handle_win.h"
#include "ipc/ipc_message_macros.h"
#define IPC_MESSAGE_START IPCTestMsgStart
+#if defined(OS_WIN)
+#include "base/memory/shared_memory_handle.h"
+#include "ipc/handle_win.h"
+
IPC_MESSAGE_CONTROL3(TestHandleWinMsg, int, IPC::HandleWin, int)
IPC_MESSAGE_CONTROL2(TestTwoHandleWinMsg, IPC::HandleWin, IPC::HandleWin)
+IPC_MESSAGE_CONTROL1(TestSharedMemoryHandleMsg1, base::SharedMemoryHandle)
#endif // defined(OS_WIN)
+
+#if defined(OS_MACOSX)
+#include "base/file_descriptor_posix.h"
+#include "base/memory/shared_memory_handle.h"
+
+IPC_MESSAGE_CONTROL3(TestSharedMemoryHandleMsg1,
+ int,
+ base::SharedMemoryHandle,
+ int)
+IPC_MESSAGE_CONTROL2(TestSharedMemoryHandleMsg2,
+ base::SharedMemoryHandle,
+ base::SharedMemoryHandle)
+IPC_MESSAGE_CONTROL4(TestSharedMemoryHandleMsg3,
+ base::FileDescriptor,
+ base::SharedMemoryHandle,
+ base::FileDescriptor,
+ base::SharedMemoryHandle)
+IPC_MESSAGE_CONTROL1(TestSharedMemoryHandleMsg4, int)
+
+#endif // defined(OS_MACOSX)
diff --git a/chromium/ipc/ipc_test_sink.cc b/chromium/ipc/ipc_test_sink.cc
index ab95a19a2ce..316609c3386 100644
--- a/chromium/ipc/ipc_test_sink.cc
+++ b/chromium/ipc/ipc_test_sink.cc
@@ -4,6 +4,10 @@
#include "ipc/ipc_test_sink.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include "build/build_config.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message.h"
diff --git a/chromium/ipc/ipc_test_sink.h b/chromium/ipc/ipc_test_sink.h
index 5539c98d7cb..ab8531d5ea8 100644
--- a/chromium/ipc/ipc_test_sink.h
+++ b/chromium/ipc/ipc_test_sink.h
@@ -5,6 +5,7 @@
#ifndef IPC_IPC_TEST_SINK_H_
#define IPC_IPC_TEST_SINK_H_
+#include <stddef.h>
#include <stdint.h>
#include <utility>
@@ -13,6 +14,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/observer_list.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel.h"
namespace IPC {
@@ -59,7 +61,7 @@ class Message;
// public:
// virtual bool OnMessageReceived(const IPC::Message& msg) {
// <do something with the message>
-// MessageLoop::current()->Quit();
+// MessageLoop::current()->QuitWhenIdle();
// return false; // to store the message in the sink, or true to drop it
// }
// };
diff --git a/chromium/ipc/ipc_tests_apk.isolate b/chromium/ipc/ipc_tests_apk.isolate
new file mode 100644
index 00000000000..0c0cf1c5ca7
--- /dev/null
+++ b/chromium/ipc/ipc_tests_apk.isolate
@@ -0,0 +1,17 @@
+# 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.
+{
+ 'includes': [
+ '../build/android/android.isolate',
+ ],
+ 'variables': {
+ 'command': [
+ '<(PRODUCT_DIR)/bin/run_ipc_tests',
+ ],
+ 'files': [
+ '<(PRODUCT_DIR)/bin/run_ipc_tests',
+ '<(PRODUCT_DIR)/ipc_tests_apk/',
+ ]
+ },
+}
diff --git a/chromium/ipc/mach_port_attachment_mac.cc b/chromium/ipc/mach_port_attachment_mac.cc
index 2a0cfa44bc8..65baa3480ed 100644
--- a/chromium/ipc/mach_port_attachment_mac.cc
+++ b/chromium/ipc/mach_port_attachment_mac.cc
@@ -4,21 +4,36 @@
#include "ipc/mach_port_attachment_mac.h"
+#include <stdint.h>
+
+#include "base/mac/mach_logging.h"
+
namespace IPC {
namespace internal {
MachPortAttachmentMac::MachPortAttachmentMac(mach_port_t mach_port)
- : mach_port_(mach_port) {}
+ : mach_port_(mach_port), owns_mach_port_(true) {
+ if (mach_port != MACH_PORT_NULL) {
+ kern_return_t kr = mach_port_mod_refs(mach_task_self(), mach_port,
+ MACH_PORT_RIGHT_SEND, 1);
+ MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+ << "MachPortAttachmentMac mach_port_mod_refs";
+ }
+}
MachPortAttachmentMac::MachPortAttachmentMac(const WireFormat& wire_format)
: BrokerableAttachment(wire_format.attachment_id),
- mach_port_(static_cast<mach_port_t>(wire_format.mach_port)) {}
-
-MachPortAttachmentMac::MachPortAttachmentMac(
- const BrokerableAttachment::AttachmentId& id)
- : BrokerableAttachment(id), mach_port_(MACH_PORT_NULL) {}
-
-MachPortAttachmentMac::~MachPortAttachmentMac() {}
+ mach_port_(static_cast<mach_port_t>(wire_format.mach_port)),
+ owns_mach_port_(true) {}
+
+MachPortAttachmentMac::~MachPortAttachmentMac() {
+ if (mach_port_ != MACH_PORT_NULL && owns_mach_port_) {
+ kern_return_t kr = mach_port_mod_refs(mach_task_self(), mach_port_,
+ MACH_PORT_RIGHT_SEND, -1);
+ MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+ << "~MachPortAttachmentMac mach_port_mod_refs";
+ }
+}
MachPortAttachmentMac::BrokerableType MachPortAttachmentMac::GetBrokerableType()
const {
diff --git a/chromium/ipc/mach_port_attachment_mac.h b/chromium/ipc/mach_port_attachment_mac.h
index efe93c46a13..244014ed724 100644
--- a/chromium/ipc/mach_port_attachment_mac.h
+++ b/chromium/ipc/mach_port_attachment_mac.h
@@ -8,6 +8,7 @@
#include <mach/mach.h>
#include <stdint.h>
+#include "base/macros.h"
#include "base/process/process_handle.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_export.h"
@@ -45,9 +46,15 @@ class IPC_EXPORT MachPortAttachmentMac : public BrokerableAttachment {
AttachmentId attachment_id;
};
+ // This constructor increments the ref count of |mach_port_| and takes
+ // ownership of the result. Should only be called by the sender of a Chrome
+ // IPC message.
explicit MachPortAttachmentMac(mach_port_t mach_port);
+
+ // This constructor takes ownership of |wire_format.mach_port|, but does not
+ // modify its ref count. Should only be called by the receiver of a Chrome IPC
+ // message.
explicit MachPortAttachmentMac(const WireFormat& wire_format);
- explicit MachPortAttachmentMac(const BrokerableAttachment::AttachmentId& id);
BrokerableType GetBrokerableType() const override;
@@ -56,9 +63,20 @@ class IPC_EXPORT MachPortAttachmentMac : public BrokerableAttachment {
mach_port_t get_mach_port() const { return mach_port_; }
+ // The caller of this method has taken ownership of |mach_port_|.
+ void reset_mach_port_ownership() { owns_mach_port_ = false; }
+
private:
~MachPortAttachmentMac() override;
- mach_port_t mach_port_;
+ const mach_port_t mach_port_;
+
+ // In the sender process, the attachment owns the Mach port of a newly created
+ // message. The attachment broker will eventually take ownership of
+ // |mach_port_|.
+ // In the destination process, the attachment owns |mach_port_| until
+ // ParamTraits<MachPortMac>::Read() is called, which takes ownership.
+ bool owns_mach_port_;
+ DISALLOW_COPY_AND_ASSIGN(MachPortAttachmentMac);
};
} // namespace internal
diff --git a/chromium/ipc/mach_port_mac.cc b/chromium/ipc/mach_port_mac.cc
index 96f4acaeb21..51a5bd7abfc 100644
--- a/chromium/ipc/mach_port_mac.cc
+++ b/chromium/ipc/mach_port_mac.cc
@@ -37,6 +37,7 @@ bool ParamTraits<MachPortMac>::Read(const Message* m,
IPC::internal::MachPortAttachmentMac* mach_port_attachment =
static_cast<IPC::internal::MachPortAttachmentMac*>(brokerable_attachment);
r->set_mach_port(mach_port_attachment->get_mach_port());
+ mach_port_attachment->reset_mach_port_ownership();
return true;
}
diff --git a/chromium/ipc/mach_port_mac.h b/chromium/ipc/mach_port_mac.h
index 0193f9dadd9..5c420c0fed3 100644
--- a/chromium/ipc/mach_port_mac.h
+++ b/chromium/ipc/mach_port_mac.h
@@ -7,24 +7,65 @@
#include <mach/mach.h>
+#include "base/macros.h"
#include "ipc/ipc_export.h"
#include "ipc/ipc_message_macros.h"
namespace IPC {
-// MachPortMac is a wrapper around an OSX mach_port_t that can be transported
-// across Chrome IPC channels that support attachment brokering. The mach_port_t
-// will be duplicated into the destination process by the attachment broker.
+// MachPortMac is a wrapper around an OSX Mach port that can be transported
+// across Chrome IPC channels that support attachment brokering. The send right
+// to the Mach port will be duplicated into the destination process by the
+// attachment broker. If needed, attachment brokering can be trivially extended
+// to support duplication of other types of rights.
class IPC_EXPORT MachPortMac {
public:
MachPortMac() : mach_port_(MACH_PORT_NULL) {}
- explicit MachPortMac(const mach_port_t& mach_port) : mach_port_(mach_port) {}
+
+ explicit MachPortMac(mach_port_t mach_port) : mach_port_(mach_port) {}
mach_port_t get_mach_port() const { return mach_port_; }
+
+ // This method should only be used by ipc/ translation code.
void set_mach_port(mach_port_t mach_port) { mach_port_ = mach_port; }
private:
+ // The ownership semantics of |mach_port_| cannot be easily expressed with a
+ // C++ scoped object. This is partly due to the mechanism by which Mach ports
+ // are brokered, and partly due to the architecture of Chrome IPC.
+ //
+ // The broker for Mach ports may live in a different process than the sender
+ // of the original Chrome IPC. In this case, it is signalled asynchronously,
+ // and ownership of the Mach port passes from the sender process into the
+ // broker process.
+ //
+ // Chrome IPC is written with the assumption that translation is a stateless
+ // process. There is no good mechanism to convey the semantics of ownership
+ // transfer from the Chrome IPC stack into the client code that receives the
+ // translated message. As a result, Chrome IPC code assumes that every message
+ // has a handler, and that the handler will take ownership of the Mach port.
+ // Note that the same holds true for POSIX fds and Windows HANDLEs.
+ //
+ // When used by client code in the sender process, this class is just a
+ // wrapper. The client code calls Send(new Message(MachPortMac(mach_port)))
+ // and continues on its merry way. Behind the scenes, a MachPortAttachmentMac
+ // takes ownership of the Mach port. When the attachment broker sends the name
+ // of the Mach port to the broker process, it also releases
+ // MachPortAttachmentMac's reference to the Mach port, as ownership has
+ // effectively been transferred to the broker process.
+ //
+ // The broker process receives the name, duplicates the Mach port into the
+ // destination process, and then decrements the ref count in the original
+ // process.
+ //
+ // In the destination process, the attachment broker is responsible for
+ // coupling the Mach port (inserted by the broker process) with Chrome IPC in
+ // the form of a MachPortAttachmentMac. Due to the Chrome IPC translation
+ // semantics discussed above, this MachPortAttachmentMac does not take
+ // ownership of the Mach port, and assumes that the client code which receives
+ // the callback will take ownership of the Mach port.
mach_port_t mach_port_;
+ DISALLOW_COPY_AND_ASSIGN(MachPortMac);
};
template <>
diff --git a/chromium/ipc/message_filter.cc b/chromium/ipc/message_filter.cc
index b9436e234ac..dd5ec30fe41 100644
--- a/chromium/ipc/message_filter.cc
+++ b/chromium/ipc/message_filter.cc
@@ -4,6 +4,8 @@
#include "ipc/message_filter.h"
+#include <stdint.h>
+
#include "base/memory/ref_counted.h"
#include "ipc/ipc_channel.h"
diff --git a/chromium/ipc/message_filter_router.cc b/chromium/ipc/message_filter_router.cc
index 35209b09181..56075d68891 100644
--- a/chromium/ipc/message_filter_router.cc
+++ b/chromium/ipc/message_filter_router.cc
@@ -4,8 +4,10 @@
#include "ipc/message_filter_router.h"
+#include <stddef.h>
#include <stdint.h>
+#include "base/macros.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/message_filter.h"
diff --git a/chromium/ipc/mojo/BUILD.gn b/chromium/ipc/mojo/BUILD.gn
index d801a7b9c19..29e3a957420 100644
--- a/chromium/ipc/mojo/BUILD.gn
+++ b/chromium/ipc/mojo/BUILD.gn
@@ -2,8 +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 = [
@@ -35,14 +35,14 @@ component("mojo") {
defines = [ "IPC_MOJO_IMPLEMENTATION" ]
deps = [
+ ":client_channel",
"//base",
"//base/third_party/dynamic_annotations",
"//ipc",
"//mojo/environment:chromium",
+ "//mojo/public/c/environment:environment",
+ "//mojo/public/cpp/bindings",
"//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",
]
}
diff --git a/chromium/ipc/mojo/DEPS b/chromium/ipc/mojo/DEPS
index 40dca36e2df..59e80a9bf82 100644
--- a/chromium/ipc/mojo/DEPS
+++ b/chromium/ipc/mojo/DEPS
@@ -1,5 +1,5 @@
include_rules = [
"+mojo/edk/embedder",
- "+third_party/mojo/src/mojo/public",
+ "+mojo/public",
"+third_party/mojo/src/mojo/edk/embedder",
]
diff --git a/chromium/ipc/mojo/OWNERS b/chromium/ipc/mojo/OWNERS
index 584a1f68941..ae47a47a0f7 100644
--- a/chromium/ipc/mojo/OWNERS
+++ b/chromium/ipc/mojo/OWNERS
@@ -1,2 +1,4 @@
+amistry@chromium.org
morrita@chromium.org
-viettrungluu@chromium.org \ No newline at end of file
+rockot@chromium.org
+viettrungluu@chromium.org
diff --git a/chromium/ipc/mojo/async_handle_waiter.cc b/chromium/ipc/mojo/async_handle_waiter.cc
index 652764edc6c..4e07480f6cf 100644
--- a/chromium/ipc/mojo/async_handle_waiter.cc
+++ b/chromium/ipc/mojo/async_handle_waiter.cc
@@ -9,6 +9,7 @@
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
namespace IPC {
diff --git a/chromium/ipc/mojo/async_handle_waiter.h b/chromium/ipc/mojo/async_handle_waiter.h
index d6cc74510b2..e82c27ae29c 100644
--- a/chromium/ipc/mojo/async_handle_waiter.h
+++ b/chromium/ipc/mojo/async_handle_waiter.h
@@ -6,11 +6,12 @@
#define IPC_MOJO_ASYNC_HANDLE_WAITER_H_
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "ipc/ipc_export.h"
-#include "third_party/mojo/src/mojo/public/c/system/types.h"
+#include "mojo/public/c/system/types.h"
namespace IPC {
namespace internal {
diff --git a/chromium/ipc/mojo/async_handle_waiter_unittest.cc b/chromium/ipc/mojo/async_handle_waiter_unittest.cc
index 46d4c7ef739..e17b4fd3b09 100644
--- a/chromium/ipc/mojo/async_handle_waiter_unittest.cc
+++ b/chromium/ipc/mojo/async_handle_waiter_unittest.cc
@@ -4,13 +4,16 @@
#include "ipc/mojo/async_handle_waiter.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
+#include "mojo/public/cpp/system/message_pipe.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
namespace IPC {
namespace internal {
diff --git a/chromium/ipc/mojo/ipc_channel_mojo.cc b/chromium/ipc/mojo/ipc_channel_mojo.cc
index 3f4d31f7230..404c814516e 100644
--- a/chromium/ipc/mojo/ipc_channel_mojo.cc
+++ b/chromium/ipc/mojo/ipc_channel_mojo.cc
@@ -4,11 +4,18 @@
#include "ipc/mojo/ipc_channel_mojo.h"
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_logging.h"
#include "ipc/ipc_message_attachment_set.h"
@@ -16,9 +23,8 @@
#include "ipc/mojo/client_channel.mojom.h"
#include "ipc/mojo/ipc_mojo_bootstrap.h"
#include "ipc/mojo/ipc_mojo_handle_attachment.h"
-#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
#if defined(OS_POSIX) && !defined(OS_NACL)
#include "ipc/ipc_platform_file_attachment_posix.h"
@@ -68,20 +74,19 @@ class ClientChannelMojo : public ChannelMojo, public ClientChannel {
// MojoBootstrap::Delegate implementation
void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle,
- int32 peer_pid) override {
+ int32_t peer_pid) override {
if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
- mojo::edk::ScopedPlatformHandle edk_handle(mojo::edk::PlatformHandle(
-#if defined(OS_WIN)
- handle.release().handle));
-#else
- handle.release().fd));
-#endif
InitMessageReader(
- mojo::edk::CreateMessagePipe(edk_handle.Pass()), peer_pid);
+ mojo::embedder::CreateChannel(
+ std::move(handle),
+ base::Callback<void(mojo::embedder::ChannelInfo*)>(),
+ scoped_refptr<base::TaskRunner>()),
+ peer_pid);
return;
}
- CreateMessagingPipe(handle.Pass(), base::Bind(&ClientChannelMojo::BindPipe,
- weak_factory_.GetWeakPtr()));
+ CreateMessagingPipe(
+ std::move(handle),
+ base::Bind(&ClientChannelMojo::BindPipe, weak_factory_.GetWeakPtr()));
}
// ClientChannel implementation
@@ -89,13 +94,13 @@ class ClientChannelMojo : public ChannelMojo, public ClientChannel {
mojo::ScopedMessagePipeHandle pipe,
int32_t peer_pid,
const mojo::Callback<void(int32_t)>& callback) override {
- InitMessageReader(pipe.Pass(), static_cast<base::ProcessId>(peer_pid));
+ InitMessageReader(std::move(pipe), static_cast<base::ProcessId>(peer_pid));
callback.Run(GetSelfPID());
}
private:
void BindPipe(mojo::ScopedMessagePipeHandle handle) {
- binding_.Bind(handle.Pass());
+ binding_.Bind(std::move(handle));
}
void OnConnectionError() {
listener()->OnChannelError();
@@ -123,21 +128,18 @@ class ServerChannelMojo : public ChannelMojo {
// MojoBootstrap::Delegate implementation
void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle,
- int32 peer_pid) override {
+ int32_t peer_pid) override {
if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
- mojo::edk::ScopedPlatformHandle edk_handle(mojo::edk::PlatformHandle(
-#if defined(OS_WIN)
- handle.release().handle));
-#else
- handle.release().fd));
-#endif
- message_pipe_ = mojo::edk::CreateMessagePipe(edk_handle.Pass());
+ message_pipe_ = mojo::embedder::CreateChannel(
+ std::move(handle),
+ base::Callback<void(mojo::embedder::ChannelInfo*)>(),
+ scoped_refptr<base::TaskRunner>());
if (!message_pipe_.is_valid()) {
LOG(WARNING) << "mojo::CreateMessagePipe failed: ";
listener()->OnChannelError();
return;
}
- InitMessageReader(message_pipe_.Pass(), peer_pid);
+ InitMessageReader(std::move(message_pipe_), peer_pid);
return;
}
@@ -150,7 +152,7 @@ class ServerChannelMojo : public ChannelMojo {
return;
}
CreateMessagingPipe(
- handle.Pass(),
+ std::move(handle),
base::Bind(&ServerChannelMojo::InitClientChannel,
weak_factory_.GetWeakPtr(), base::Passed(&peer)));
}
@@ -165,11 +167,11 @@ class ServerChannelMojo : public ChannelMojo {
void InitClientChannel(mojo::ScopedMessagePipeHandle peer_handle,
mojo::ScopedMessagePipeHandle handle) {
client_channel_.Bind(
- mojo::InterfacePtrInfo<ClientChannel>(handle.Pass(), 0u));
+ mojo::InterfacePtrInfo<ClientChannel>(std::move(handle), 0u));
client_channel_.set_connection_error_handler(base::Bind(
&ServerChannelMojo::OnConnectionError, base::Unretained(this)));
client_channel_->Init(
- peer_handle.Pass(), static_cast<int32_t>(GetSelfPID()),
+ std::move(peer_handle), static_cast<int32_t>(GetSelfPID()),
base::Bind(&ServerChannelMojo::ClientChannelWasInitialized,
base::Unretained(this)));
}
@@ -180,7 +182,7 @@ class ServerChannelMojo : public ChannelMojo {
// ClientChannelClient implementation
void ClientChannelWasInitialized(int32_t peer_pid) {
- InitMessageReader(message_pipe_.Pass(), peer_pid);
+ InitMessageReader(std::move(message_pipe_), peer_pid);
}
mojo::InterfacePtr<ClientChannel> client_channel_;
@@ -303,8 +305,9 @@ void ChannelMojo::CreateMessagingPipe(
weak_factory_.GetWeakPtr(), callback);
if (!g_use_channel_on_io_thread_only ||
base::ThreadTaskRunnerHandle::Get() == io_runner_) {
- CreateMessagingPipeOnIOThread(
- handle.Pass(), base::ThreadTaskRunnerHandle::Get(), return_callback);
+ CreateMessagingPipeOnIOThread(std::move(handle),
+ base::ThreadTaskRunnerHandle::Get(),
+ return_callback);
} else {
io_runner_->PostTask(
FROM_HERE,
@@ -321,9 +324,9 @@ void ChannelMojo::CreateMessagingPipeOnIOThread(
const CreateMessagingPipeOnIOThreadCallback& callback) {
mojo::embedder::ChannelInfo* channel_info;
mojo::ScopedMessagePipeHandle pipe =
- mojo::embedder::CreateChannelOnIOThread(handle.Pass(), &channel_info);
+ mojo::embedder::CreateChannelOnIOThread(std::move(handle), &channel_info);
if (base::ThreadTaskRunnerHandle::Get() == callback_runner) {
- callback.Run(pipe.Pass(), channel_info);
+ callback.Run(std::move(pipe), channel_info);
} else {
callback_runner->PostTask(
FROM_HERE, base::Bind(callback, base::Passed(&pipe), channel_info));
@@ -337,7 +340,7 @@ void ChannelMojo::OnMessagingPipeCreated(
DCHECK(!channel_info_.get());
channel_info_ = scoped_ptr<mojo::embedder::ChannelInfo, ChannelInfoDeleter>(
channel_info, ChannelInfoDeleter(io_runner_));
- callback.Run(handle.Pass());
+ callback.Run(std::move(handle));
}
bool ChannelMojo::Connect() {
@@ -352,7 +355,7 @@ void ChannelMojo::Close() {
// |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();
+ to_be_deleted = std::move(message_reader_);
// We might Close() before we Connect().
waiting_connect_ = false;
}
@@ -371,7 +374,7 @@ namespace {
// ClosingDeleter calls |CloseWithErrorIfPending| before deleting the
// |MessagePipeReader|.
struct ClosingDeleter {
- typedef base::DefaultDeleter<internal::MessagePipeReader> DefaultType;
+ typedef std::default_delete<internal::MessagePipeReader> DefaultType;
void operator()(internal::MessagePipeReader* ptr) const {
ptr->CloseWithErrorIfPending();
@@ -384,7 +387,7 @@ struct ClosingDeleter {
void ChannelMojo::InitMessageReader(mojo::ScopedMessagePipeHandle pipe,
int32_t peer_pid) {
scoped_ptr<internal::MessagePipeReader, ClosingDeleter> reader(
- new internal::MessagePipeReader(pipe.Pass(), this));
+ new internal::MessagePipeReader(std::move(pipe), this));
{
base::AutoLock l(lock_);
@@ -475,8 +478,9 @@ MojoResult ChannelMojo::ReadFromMessageAttachmentSet(
// 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);
+ for (unsigned i = 0; i < set->num_non_brokerable_attachments(); ++i) {
+ scoped_refptr<MessageAttachment> attachment =
+ set->GetNonBrokerableAttachmentAt(i);
switch (attachment->GetType()) {
case MessageAttachment::TYPE_PLATFORM_FILE:
#if defined(OS_POSIX) && !defined(OS_NACL)
@@ -486,7 +490,7 @@ MojoResult ChannelMojo::ReadFromMessageAttachmentSet(
attachment.get()));
if (!file.is_valid()) {
DPLOG(WARNING) << "Failed to dup FD to transmit.";
- set->CommitAll();
+ set->CommitAllDescriptors();
return MOJO_RESULT_UNKNOWN;
}
@@ -498,7 +502,7 @@ MojoResult ChannelMojo::ReadFromMessageAttachmentSet(
if (MOJO_RESULT_OK != wrap_result) {
LOG(WARNING) << "Pipe failed to wrap handles. Closing: "
<< wrap_result;
- set->CommitAll();
+ set->CommitAllDescriptors();
return wrap_result;
}
@@ -522,7 +526,7 @@ MojoResult ChannelMojo::ReadFromMessageAttachmentSet(
}
}
- set->CommitAll();
+ set->CommitAllDescriptors();
}
return MOJO_RESULT_OK;
diff --git a/chromium/ipc/mojo/ipc_channel_mojo.h b/chromium/ipc/mojo/ipc_channel_mojo.h
index 834fd420da2..a5ddf1e4077 100644
--- a/chromium/ipc/mojo/ipc_channel_mojo.h
+++ b/chromium/ipc/mojo/ipc_channel_mojo.h
@@ -5,20 +5,24 @@
#ifndef IPC_IPC_CHANNEL_MOJO_H_
#define IPC_IPC_CHANNEL_MOJO_H_
+#include <stdint.h>
+
#include <vector>
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_channel_factory.h"
#include "ipc/ipc_export.h"
#include "ipc/mojo/ipc_message_pipe_reader.h"
#include "ipc/mojo/ipc_mojo_bootstrap.h"
#include "ipc/mojo/scoped_ipc_support.h"
+#include "mojo/public/cpp/system/core.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 {
diff --git a/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc b/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc
index 58d3e9f7e98..b4f4154c67c 100644
--- a/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc
+++ b/chromium/ipc/mojo/ipc_channel_mojo_unittest.cc
@@ -4,7 +4,9 @@
#include "ipc/mojo/ipc_channel_mojo.h"
+#include <stddef.h>
#include <stdint.h>
+#include <utility>
#include "base/base_paths.h"
#include "base/files/file.h"
@@ -16,6 +18,7 @@
#include "base/test/test_timeouts.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_test_base.h"
#include "ipc/ipc_test_channel_listener.h"
@@ -44,7 +47,7 @@ class ListenerThatExpectsOK : public IPC::Listener {
EXPECT_TRUE(iter.ReadString(&should_be_ok));
EXPECT_EQ(should_be_ok, "OK");
received_ok_ = true;
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
return true;
}
@@ -202,14 +205,14 @@ class ListenerExpectingErrors : public IPC::Listener {
}
void OnChannelConnected(int32_t peer_pid) override {
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
bool OnMessageReceived(const IPC::Message& message) override { return true; }
void OnChannelError() override {
has_error_ = true;
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
bool has_error() const { return has_error_; }
@@ -244,7 +247,7 @@ class ListenerThatQuits : public IPC::Listener {
}
void OnChannelConnected(int32_t peer_pid) override {
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
};
@@ -314,8 +317,8 @@ class HandleSendingHelper {
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()));
+ EXPECT_TRUE(IPC::MojoMessageHelper::WriteMessagePipeTo(
+ message, std::move(pipe->peer)));
}
static void WritePipeThenSend(IPC::Sender* sender, TestingMessagePipe* pipe) {
@@ -394,7 +397,7 @@ class ListenerThatExpectsMessagePipe : public IPC::Listener {
bool OnMessageReceived(const IPC::Message& message) override {
base::PickleIterator iter(message);
HandleSendingHelper::ReadReceivedPipe(message, &iter);
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
ListenerThatExpectsOK::SendOK(sender_);
return true;
}
@@ -478,7 +481,7 @@ class ListenerThatExpectsMessagePipeUsingParamTrait : public IPC::Listener {
MojoClose(handle.value());
}
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
ListenerThatExpectsOK::SendOK(sender_);
return true;
}
@@ -597,7 +600,7 @@ class ListenerSendingOneOk : public IPC::Listener {
void OnChannelConnected(int32_t peer_pid) override {
ListenerThatExpectsOK::SendOK(sender_);
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
void set_sender(IPC::Sender* sender) { sender_ = sender; }
@@ -686,7 +689,7 @@ class ListenerThatExpectsFile : public IPC::Listener {
bool OnMessageReceived(const IPC::Message& message) override {
base::PickleIterator iter(message);
HandleSendingHelper::ReadReceivedFile(message, &iter);
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
ListenerThatExpectsOK::SendOK(sender_);
return true;
}
@@ -751,7 +754,7 @@ class ListenerThatExpectsFileAndPipe : public IPC::Listener {
base::PickleIterator iter(message);
HandleSendingHelper::ReadReceivedFile(message, &iter);
HandleSendingHelper::ReadReceivedPipe(message, &iter);
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
ListenerThatExpectsOK::SendOK(sender_);
return true;
}
@@ -816,7 +819,7 @@ class ListenerThatVerifiesPeerPid : public IPC::Listener {
public:
void OnChannelConnected(int32_t peer_pid) override {
EXPECT_EQ(peer_pid, kMagicChildId);
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
bool OnMessageReceived(const IPC::Message& message) override {
diff --git a/chromium/ipc/mojo/ipc_message_pipe_reader.cc b/chromium/ipc/mojo/ipc_message_pipe_reader.cc
index 11aab8d6155..19d9e303a6d 100644
--- a/chromium/ipc/mojo/ipc_message_pipe_reader.cc
+++ b/chromium/ipc/mojo/ipc_message_pipe_reader.cc
@@ -5,6 +5,7 @@
#include "ipc/mojo/ipc_message_pipe_reader.h"
#include <stdint.h>
+#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -20,14 +21,12 @@ namespace internal {
MessagePipeReader::MessagePipeReader(mojo::ScopedMessagePipeHandle handle,
MessagePipeReader::Delegate* delegate)
- : pipe_(handle.Pass()),
+ : pipe_(std::move(handle)),
handle_copy_(pipe_.get().value()),
delegate_(delegate),
- async_waiter_(
- new AsyncHandleWaiter(base::Bind(&MessagePipeReader::PipeIsReady,
- base::Unretained(this)))),
- pending_send_error_(MOJO_RESULT_OK) {
-}
+ async_waiter_(new AsyncHandleWaiter(
+ base::Bind(&MessagePipeReader::PipeIsReady, base::Unretained(this)))),
+ pending_send_error_(MOJO_RESULT_OK) {}
MessagePipeReader::~MessagePipeReader() {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromium/ipc/mojo/ipc_message_pipe_reader.h b/chromium/ipc/mojo/ipc_message_pipe_reader.h
index b9c11c60372..375812305ca 100644
--- a/chromium/ipc/mojo/ipc_message_pipe_reader.h
+++ b/chromium/ipc/mojo/ipc_message_pipe_reader.h
@@ -5,15 +5,19 @@
#ifndef IPC_IPC_MESSAGE_PIPE_READER_H_
#define IPC_IPC_MESSAGE_PIPE_READER_H_
+#include <stdint.h>
+
+#include <memory>
#include <vector>
#include "base/atomicops.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.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"
+#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/public/cpp/system/core.h"
namespace IPC {
namespace internal {
@@ -49,7 +53,7 @@ class MessagePipeReader {
// This is intended to used by MessagePipeReader owners.
class DelayedDeleter {
public:
- typedef base::DefaultDeleter<MessagePipeReader> DefaultType;
+ typedef std::default_delete<MessagePipeReader> DefaultType;
static void DeleteNow(MessagePipeReader* ptr) { delete ptr; }
diff --git a/chromium/ipc/mojo/ipc_mojo_bootstrap.cc b/chromium/ipc/mojo/ipc_mojo_bootstrap.cc
index b668a7bcac2..d2966756605 100644
--- a/chromium/ipc/mojo/ipc_mojo_bootstrap.cc
+++ b/chromium/ipc/mojo/ipc_mojo_bootstrap.cc
@@ -5,9 +5,12 @@
#include "ipc/mojo/ipc_mojo_bootstrap.h"
#include <stdint.h>
+#include <utility>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/process/process_handle.h"
+#include "build/build_config.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_platform_file.h"
#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
@@ -109,7 +112,7 @@ class MojoClientBootstrap : public MojoBootstrap {
bool OnMessageReceived(const Message& message) override;
void OnChannelConnected(int32_t peer_pid) override;
- int32 peer_pid_;
+ int32_t peer_pid_;
DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap);
};
@@ -162,8 +165,8 @@ scoped_ptr<MojoBootstrap> MojoBootstrap::Create(ChannelHandle handle,
scoped_ptr<Channel> bootstrap_channel =
Channel::Create(handle, mode, self.get());
- self->Init(bootstrap_channel.Pass(), delegate);
- return self.Pass();
+ self->Init(std::move(bootstrap_channel), delegate);
+ return self;
}
MojoBootstrap::MojoBootstrap() : delegate_(NULL), state_(STATE_INITIALIZED) {
@@ -173,7 +176,7 @@ MojoBootstrap::~MojoBootstrap() {
}
void MojoBootstrap::Init(scoped_ptr<Channel> channel, Delegate* delegate) {
- channel_ = channel.Pass();
+ channel_ = std::move(channel);
delegate_ = delegate;
}
diff --git a/chromium/ipc/mojo/ipc_mojo_bootstrap.h b/chromium/ipc/mojo/ipc_mojo_bootstrap.h
index 27a038baa5e..4b5ccfb71e9 100644
--- a/chromium/ipc/mojo/ipc_mojo_bootstrap.h
+++ b/chromium/ipc/mojo/ipc_mojo_bootstrap.h
@@ -5,8 +5,12 @@
#ifndef IPC_MOJO_IPC_MOJO_BOOTSTRAP_H_
#define IPC_MOJO_IPC_MOJO_BOOTSTRAP_H_
+#include <stdint.h>
+
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/process_handle.h"
+#include "build/build_config.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_listener.h"
#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
@@ -27,9 +31,8 @@ class IPC_MOJO_EXPORT MojoBootstrap : public Listener {
public:
class Delegate {
public:
- virtual void OnPipeAvailable(
- mojo::embedder::ScopedPlatformHandle handle,
- int32 peer_pid) = 0;
+ virtual void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle,
+ int32_t peer_pid) = 0;
virtual void OnBootstrapError() = 0;
};
diff --git a/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc b/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc
index 528c2350332..60046d16c52 100644
--- a/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc
+++ b/chromium/ipc/mojo/ipc_mojo_bootstrap_unittest.cc
@@ -4,9 +4,12 @@
#include "ipc/mojo/ipc_mojo_bootstrap.h"
+#include <stdint.h>
+
#include "base/base_paths.h"
#include "base/files/file.h"
#include "base/message_loop/message_loop.h"
+#include "build/build_config.h"
#include "ipc/ipc_test_base.h"
#if defined(OS_POSIX)
@@ -24,7 +27,7 @@ class TestingDelegate : public IPC::MojoBootstrap::Delegate {
TestingDelegate() : passed_(false) {}
void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle,
- int32 peer_pid) override;
+ int32_t peer_pid) override;
void OnBootstrapError() override;
bool passed() const { return passed_; }
@@ -35,13 +38,13 @@ class TestingDelegate : public IPC::MojoBootstrap::Delegate {
void TestingDelegate::OnPipeAvailable(
mojo::embedder::ScopedPlatformHandle handle,
- int32 peer_pid) {
+ int32_t peer_pid) {
passed_ = true;
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
void TestingDelegate::OnBootstrapError() {
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
// Times out on Android; see http://crbug.com/502290
diff --git a/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc b/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc
index 9aae281c4ec..70b80c57b13 100644
--- a/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc
+++ b/chromium/ipc/mojo/ipc_mojo_handle_attachment.cc
@@ -4,6 +4,9 @@
#include "ipc/mojo/ipc_mojo_handle_attachment.h"
+#include <utility>
+
+#include "build/build_config.h"
#include "ipc/ipc_message_attachment_set.h"
#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
@@ -11,8 +14,7 @@ namespace IPC {
namespace internal {
MojoHandleAttachment::MojoHandleAttachment(mojo::ScopedHandle handle)
- : handle_(handle.Pass()) {
-}
+ : handle_(std::move(handle)) {}
MojoHandleAttachment::~MojoHandleAttachment() {
}
@@ -37,7 +39,7 @@ base::PlatformFile MojoHandleAttachment::TakePlatformFile() {
#endif // OS_POSIX
mojo::ScopedHandle MojoHandleAttachment::TakeHandle() {
- return handle_.Pass();
+ return std::move(handle_);
}
} // namespace internal
diff --git a/chromium/ipc/mojo/ipc_mojo_handle_attachment.h b/chromium/ipc/mojo/ipc_mojo_handle_attachment.h
index ef5a318ec72..2d51879c7af 100644
--- a/chromium/ipc/mojo/ipc_mojo_handle_attachment.h
+++ b/chromium/ipc/mojo/ipc_mojo_handle_attachment.h
@@ -6,9 +6,11 @@
#define IPC_MOJO_IPC_MOJO_HANDLE_ATTACHMENT_H_
#include "base/files/file.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#include "ipc/ipc_export.h"
#include "ipc/ipc_message_attachment.h"
-#include "third_party/mojo/src/mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/handle.h"
namespace IPC {
diff --git a/chromium/ipc/mojo/ipc_mojo_message_helper.cc b/chromium/ipc/mojo/ipc_mojo_message_helper.cc
index 6f33f80f11b..8b8344ec766 100644
--- a/chromium/ipc/mojo/ipc_mojo_message_helper.cc
+++ b/chromium/ipc/mojo/ipc_mojo_message_helper.cc
@@ -4,6 +4,8 @@
#include "ipc/mojo/ipc_mojo_message_helper.h"
+#include <utility>
+
#include "ipc/mojo/ipc_mojo_handle_attachment.h"
namespace IPC {
@@ -13,7 +15,7 @@ bool MojoMessageHelper::WriteMessagePipeTo(
Message* message,
mojo::ScopedMessagePipeHandle handle) {
message->WriteAttachment(new internal::MojoHandleAttachment(
- mojo::ScopedHandle::From(handle.Pass())));
+ mojo::ScopedHandle::From(std::move(handle))));
return true;
}
diff --git a/chromium/ipc/mojo/ipc_mojo_message_helper.h b/chromium/ipc/mojo/ipc_mojo_message_helper.h
index 2efa1390aee..3dc840e92e3 100644
--- a/chromium/ipc/mojo/ipc_mojo_message_helper.h
+++ b/chromium/ipc/mojo/ipc_mojo_message_helper.h
@@ -7,7 +7,7 @@
#include "ipc/ipc_export.h"
#include "ipc/ipc_message.h"
-#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
+#include "mojo/public/cpp/system/message_pipe.h"
namespace IPC {
diff --git a/chromium/ipc/mojo/ipc_mojo_param_traits.h b/chromium/ipc/mojo/ipc_mojo_param_traits.h
index c735fce370d..f0b8b515b6f 100644
--- a/chromium/ipc/mojo/ipc_mojo_param_traits.h
+++ b/chromium/ipc/mojo/ipc_mojo_param_traits.h
@@ -9,7 +9,7 @@
#include "ipc/ipc_export.h"
#include "ipc/ipc_param_traits.h"
-#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
+#include "mojo/public/cpp/system/message_pipe.h"
namespace base {
class PickleIterator;
diff --git a/chromium/ipc/mojo/ipc_mojo_perftest.cc b/chromium/ipc/mojo/ipc_mojo_perftest.cc
index 1c84f2cc919..d782c77ee59 100644
--- a/chromium/ipc/mojo/ipc_mojo_perftest.cc
+++ b/chromium/ipc/mojo/ipc_mojo_perftest.cc
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/lazy_instance.h"
#include "base/run_loop.h"
+#include "build/build_config.h"
#include "ipc/ipc_perftest_support.h"
#include "ipc/mojo/ipc_channel_mojo.h"
-#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
namespace {
diff --git a/chromium/ipc/mojo/run_all_unittests.cc b/chromium/ipc/mojo/run_all_unittests.cc
index 63824745c0a..43a1e4e0e8d 100644
--- a/chromium/ipc/mojo/run_all_unittests.cc
+++ b/chromium/ipc/mojo/run_all_unittests.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
+#include "build/build_config.h"
#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
#if defined(OS_ANDROID)
@@ -13,30 +14,14 @@
#include "base/test/test_file_util.h"
#endif
-namespace {
-
-class NoAtExitBaseTestSuite : public base::TestSuite {
- public:
- NoAtExitBaseTestSuite(int argc, char** argv)
- : base::TestSuite(argc, argv, false) {
- }
-};
-
-int RunTestSuite(int argc, char** argv) {
- return NoAtExitBaseTestSuite(argc, argv).Run();
-}
-
-} // namespace
-
int main(int argc, char** argv) {
- mojo::embedder::Init();
#if defined(OS_ANDROID)
JNIEnv* env = base::android::AttachCurrentThread();
base::RegisterContentUriTestUtils(env);
-#else
- base::AtExitManager at_exit;
#endif
- return base::LaunchUnitTestsSerially(argc,
- argv,
- base::Bind(&RunTestSuite, argc, argv));
+ base::TestSuite test_suite(argc, argv);
+ mojo::embedder::Init();
+ return base::LaunchUnitTestsSerially(
+ argc, argv,
+ base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
}
diff --git a/chromium/ipc/mojo/scoped_ipc_support.cc b/chromium/ipc/mojo/scoped_ipc_support.cc
index 572946373e3..15575444e64 100644
--- a/chromium/ipc/mojo/scoped_ipc_support.cc
+++ b/chromium/ipc/mojo/scoped_ipc_support.cc
@@ -4,9 +4,12 @@
#include "ipc/mojo/scoped_ipc_support.h"
+#include <stddef.h>
+
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
@@ -31,10 +34,7 @@ class IPCSupportInitializer : public mojo::embedder::ProcessDelegate {
~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();
+ void ShutDown(bool force);
private:
// This watches for destruction of the MessageLoop that IPCSupportInitializer
@@ -52,7 +52,7 @@ class IPCSupportInitializer : public mojo::embedder::ProcessDelegate {
private:
// base::MessageLoop::DestructionObserver:
void WillDestroyCurrentMessageLoop() override {
- initializer_->ForceShutdown();
+ initializer_->ShutDown(true);
}
IPCSupportInitializer* initializer_;
@@ -107,29 +107,21 @@ void IPCSupportInitializer::Init(
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());
+ mojo::embedder::ProcessType::NONE, 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() {
+void IPCSupportInitializer::ShutDown(bool force) {
base::AutoLock locker(lock_);
if (shutting_down_ || was_shut_down_)
return;
+ DCHECK(init_count_ > 0);
+ if (init_count_ > 1 && !force) {
+ init_count_--;
+ return;
+ }
+
shutting_down_ = true;
if (base::MessageLoop::current() &&
base::MessageLoop::current()->task_runner() == io_thread_task_runner_) {
@@ -173,7 +165,7 @@ ScopedIPCSupport::ScopedIPCSupport(
}
ScopedIPCSupport::~ScopedIPCSupport() {
- ipc_support_initializer.Get().ShutDown();
+ ipc_support_initializer.Get().ShutDown(false);
}
} // namespace IPC
diff --git a/chromium/ipc/placeholder_brokerable_attachment.h b/chromium/ipc/placeholder_brokerable_attachment.h
index 7a63c729bb0..a8b08ef5ae5 100644
--- a/chromium/ipc/placeholder_brokerable_attachment.h
+++ b/chromium/ipc/placeholder_brokerable_attachment.h
@@ -5,6 +5,7 @@
#ifndef IPC_PLACEHOLDER_BROKERABLE_ATTACHMENT_H_
#define IPC_PLACEHOLDER_BROKERABLE_ATTACHMENT_H_
+#include "base/macros.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/ipc_export.h"
diff --git a/chromium/ipc/run_all_unittests.cc b/chromium/ipc/run_all_unittests.cc
index a488802156a..26a73955eaf 100644
--- a/chromium/ipc/run_all_unittests.cc
+++ b/chromium/ipc/run_all_unittests.cc
@@ -2,39 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/at_exit.h"
#include "base/bind.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
#include "base/test/test_file_util.h"
#endif
-namespace {
-
-class NoAtExitBaseTestSuite : public base::TestSuite {
- public:
- NoAtExitBaseTestSuite(int argc, char** argv)
- : base::TestSuite(argc, argv, false) {
- }
-};
-
-int RunTestSuite(int argc, char** argv) {
- return NoAtExitBaseTestSuite(argc, argv).Run();
-}
-
-} // namespace
-
int main(int argc, char** argv) {
#if defined(OS_ANDROID)
JNIEnv* env = base::android::AttachCurrentThread();
base::RegisterContentUriTestUtils(env);
-#else
- base::AtExitManager at_exit;
#endif
- return base::LaunchUnitTestsSerially(argc,
- argv,
- base::Bind(&RunTestSuite, argc, argv));
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv,
+ base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
}
diff --git a/chromium/ipc/sync_socket_unittest.cc b/chromium/ipc/sync_socket_unittest.cc
index 9bf19dd6f86..89c155b0613 100644
--- a/chromium/ipc/sync_socket_unittest.cc
+++ b/chromium/ipc/sync_socket_unittest.cc
@@ -4,14 +4,17 @@
#include "base/sync_socket.h"
+#include <stddef.h>
#include <stdio.h>
#include <sstream>
#include <string>
#include "base/bind.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "ipc/ipc_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -95,9 +98,7 @@ class SyncSocketServerListener : public IPC::Listener {
// When the client responds, it sends back a shutdown message,
// which causes the message loop to exit.
- void OnMsgClassShutdown() {
- base::MessageLoop::current()->Quit();
- }
+ void OnMsgClassShutdown() { base::MessageLoop::current()->QuitWhenIdle(); }
IPC::Channel* chan_;
@@ -153,7 +154,7 @@ class SyncSocketClientListener : public IPC::Listener {
EXPECT_EQ(0U, socket_->Peek());
IPC::Message* msg = new MsgClassShutdown();
EXPECT_TRUE(chan_->Send(msg));
- base::MessageLoop::current()->Quit();
+ base::MessageLoop::current()->QuitWhenIdle();
}
base::SyncSocket* socket_;
diff --git a/chromium/ipc/test_util_mac.cc b/chromium/ipc/test_util_mac.cc
new file mode 100644
index 00000000000..6b6e64bb4af
--- /dev/null
+++ b/chromium/ipc/test_util_mac.cc
@@ -0,0 +1,143 @@
+// 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/test_util_mac.h"
+
+#include <mach/mach_vm.h>
+#include <servers/bootstrap.h>
+#include <stddef.h>
+
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace {
+
+// Structs used to pass a Mach port over mach_msg().
+struct MachSendPortMessage {
+ mach_msg_header_t header;
+ mach_msg_body_t body;
+ mach_msg_port_descriptor_t data;
+};
+
+struct MachReceivePortMessage : public MachSendPortMessage {
+ mach_msg_trailer_t trailer;
+};
+
+} // namespace
+
+namespace IPC {
+
+std::string CreateRandomServiceName() {
+ return base::StringPrintf("TestUtilMac.%llu", base::RandUint64());
+}
+
+base::mac::ScopedMachReceiveRight BecomeMachServer(const char* service_name) {
+ mach_port_t port;
+ kern_return_t kr = bootstrap_check_in(bootstrap_port, service_name, &port);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "BecomeMachServer ";
+ return base::mac::ScopedMachReceiveRight(port);
+}
+
+base::mac::ScopedMachSendRight LookupServer(const char* service_name) {
+ mach_port_t server_port;
+ kern_return_t kr =
+ bootstrap_look_up(bootstrap_port, service_name, &server_port);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "LookupServer";
+ return base::mac::ScopedMachSendRight(server_port);
+}
+
+base::mac::ScopedMachReceiveRight MakeReceivingPort() {
+ mach_port_t client_port;
+ kern_return_t kr = mach_port_allocate(mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE, &client_port);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "MakeReceivingPort";
+ return base::mac::ScopedMachReceiveRight(client_port);
+}
+
+base::mac::ScopedMachSendRight ReceiveMachPort(mach_port_t port_to_listen_on) {
+ MachReceivePortMessage recv_msg;
+ mach_msg_header_t* recv_hdr = &recv_msg.header;
+ recv_hdr->msgh_local_port = port_to_listen_on;
+ recv_hdr->msgh_size = sizeof(recv_msg);
+ kern_return_t kr =
+ mach_msg(recv_hdr, MACH_RCV_MSG, 0, recv_hdr->msgh_size,
+ port_to_listen_on, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "ReceiveMachPort";
+ mach_port_t other_task_port = recv_msg.data.name;
+ return base::mac::ScopedMachSendRight(other_task_port);
+}
+
+// Passes a copy of the send right of |port_to_send| to |receiving_port|.
+void SendMachPort(mach_port_t receiving_port,
+ mach_port_t port_to_send,
+ int disposition) {
+ MachSendPortMessage send_msg;
+ send_msg.header.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
+ send_msg.header.msgh_size = sizeof(send_msg);
+ send_msg.header.msgh_remote_port = receiving_port;
+ send_msg.header.msgh_local_port = MACH_PORT_NULL;
+ send_msg.header.msgh_reserved = 0;
+ send_msg.header.msgh_id = 0;
+ send_msg.body.msgh_descriptor_count = 1;
+ send_msg.data.name = port_to_send;
+ send_msg.data.disposition = disposition;
+ send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR;
+ int kr = mach_msg(&send_msg.header, MACH_SEND_MSG, send_msg.header.msgh_size,
+ 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "SendMachPort";
+}
+
+mach_msg_type_number_t GetActiveNameCount() {
+ mach_port_name_array_t name_array;
+ mach_msg_type_number_t names_count;
+ mach_port_type_array_t type_array;
+ mach_msg_type_number_t types_count;
+ kern_return_t kr = mach_port_names(mach_task_self(), &name_array,
+ &names_count, &type_array, &types_count);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetActiveNameCount";
+ return names_count;
+}
+
+mach_port_urefs_t GetMachRefCount(mach_port_name_t name,
+ mach_port_right_t right) {
+ mach_port_urefs_t ref_count;
+ kern_return_t kr = mach_port_get_refs(mach_task_self(), name,
+ MACH_PORT_RIGHT_SEND, &ref_count);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetRefCount";
+ return ref_count;
+}
+
+void IncrementMachRefCount(mach_port_name_t name, mach_port_right_t right) {
+ kern_return_t kr = mach_port_mod_refs(mach_task_self(), name, right, 1);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetRefCount";
+}
+
+bool GetMachProtections(void* address, size_t size, int* current, int* max) {
+ vm_region_info_t region_info;
+ mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address);
+ mach_vm_size_t mem_size = size;
+ vm_region_basic_info_64 basic_info;
+
+ region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info);
+ vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
+ memory_object_name_t memory_object;
+ mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
+
+ kern_return_t kr =
+ mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor,
+ region_info, &count, &memory_object);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(ERROR, kr) << "Failed to get region info.";
+ return false;
+ }
+
+ *current = basic_info.protection;
+ *max = basic_info.max_protection;
+ return true;
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/test_util_mac.h b/chromium/ipc/test_util_mac.h
new file mode 100644
index 00000000000..2f5e819dd45
--- /dev/null
+++ b/chromium/ipc/test_util_mac.h
@@ -0,0 +1,61 @@
+// 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.
+
+// This file contains Mac-specific utility functions used by multiple test
+// suites.
+
+#ifndef IPC_TEST_UTIL_MAC_H_
+#define IPC_TEST_UTIL_MAC_H_
+
+#include <mach/mach.h>
+#include <stddef.h>
+
+#include <string>
+
+#include "base/mac/scoped_mach_port.h"
+
+namespace IPC {
+
+// Returns a random name suitable for Mach Server registration.
+std::string CreateRandomServiceName();
+
+// Makes the current process into a Mach Server with the given |service_name|.
+// Returns a receive right for the service port.
+base::mac::ScopedMachReceiveRight BecomeMachServer(const char* service_name);
+
+// Returns a send right to the service port for the Mach Server with the given
+// |service_name|.
+base::mac::ScopedMachSendRight LookupServer(const char* service_name);
+
+// Returns the receive right to a newly minted Mach port.
+base::mac::ScopedMachReceiveRight MakeReceivingPort();
+
+// Blocks until a Mach message is sent to |port_to_listen_on|. This Mach message
+// must contain a Mach port. Returns that Mach port.
+base::mac::ScopedMachSendRight ReceiveMachPort(mach_port_t port_to_listen_on);
+
+// Passes a copy of the send right of |port_to_send| to |receiving_port|, using
+// the given |disposition|.
+void SendMachPort(mach_port_t receiving_port,
+ mach_port_t port_to_send,
+ int disposition);
+
+// The number of active names in the current task's port name space.
+mach_msg_type_number_t GetActiveNameCount();
+
+// The number of references the current task has for a given name.
+mach_port_urefs_t GetMachRefCount(mach_port_name_t name,
+ mach_port_right_t right);
+
+// Increments the ref count for the right/name pair.
+void IncrementMachRefCount(mach_port_name_t name, mach_port_right_t right);
+
+// Gets the current and maximum protection levels of the memory region.
+// Returns whether the operation was successful.
+// |current| and |max| are output variables only populated on success.
+bool GetMachProtections(void* address, size_t size, int* current, int* max);
+
+} // namespace IPC
+
+#endif // IPC_TEST_UTIL_MAC_H_
diff --git a/chromium/ipc/unix_domain_socket_util.cc b/chromium/ipc/unix_domain_socket_util.cc
index 74053445b7a..fb64cb29165 100644
--- a/chromium/ipc/unix_domain_socket_util.cc
+++ b/chromium/ipc/unix_domain_socket_util.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
@@ -16,6 +17,7 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
namespace IPC {
diff --git a/chromium/ipc/unix_domain_socket_util.h b/chromium/ipc/unix_domain_socket_util.h
index 5752364fa10..13590722950 100644
--- a/chromium/ipc/unix_domain_socket_util.h
+++ b/chromium/ipc/unix_domain_socket_util.h
@@ -5,6 +5,7 @@
#ifndef IPC_UNIX_DOMAIN_SOCKET_UTIL_H_
#define IPC_UNIX_DOMAIN_SOCKET_UTIL_H_
+#include <stddef.h>
#include <sys/types.h>
#include <string>
diff --git a/chromium/ipc/unix_domain_socket_util_unittest.cc b/chromium/ipc/unix_domain_socket_util_unittest.cc
index 57365a5840d..49c1c024c1f 100644
--- a/chromium/ipc/unix_domain_socket_util_unittest.cc
+++ b/chromium/ipc/unix_domain_socket_util_unittest.cc
@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
#include <sys/socket.h>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
#include "base/single_thread_task_runner.h"