Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2185)

Side by Side Diff: mojo/edk/system/node_controller.cc

Issue 1712143002: [mojo-edk] Add support for transferring mach ports. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: More stuff. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "mojo/edk/system/node_controller.h" 5 #include "mojo/edk/system/node_controller.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
15 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
16 #include "base/process/process_handle.h" 16 #include "base/process/process_handle.h"
17 #include "crypto/random.h" 17 #include "crypto/random.h"
18 #include "mojo/edk/embedder/embedder_internal.h" 18 #include "mojo/edk/embedder/embedder_internal.h"
19 #include "mojo/edk/embedder/platform_channel_pair.h" 19 #include "mojo/edk/embedder/platform_channel_pair.h"
20 #include "mojo/edk/system/broker.h" 20 #include "mojo/edk/system/broker.h"
21 #include "mojo/edk/system/broker_host.h" 21 #include "mojo/edk/system/broker_host.h"
22 #include "mojo/edk/system/core.h" 22 #include "mojo/edk/system/core.h"
23 #include "mojo/edk/system/ports_message.h" 23 #include "mojo/edk/system/ports_message.h"
24 24
25 #if defined(OS_MACOSX) && !defined(OS_IOS)
26 #include "mojo/edk/system/mach_port_relay.h"
27 #endif
28
25 namespace mojo { 29 namespace mojo {
26 namespace edk { 30 namespace edk {
27 31
28 namespace { 32 namespace {
29 33
30 template <typename T> 34 template <typename T>
31 void GenerateRandomName(T* out) { crypto::RandBytes(out, sizeof(T)); } 35 void GenerateRandomName(T* out) { crypto::RandBytes(out, sizeof(T)); }
32 36
33 ports::NodeName GetRandomNodeName() { 37 ports::NodeName GetRandomNodeName() {
34 ports::NodeName name; 38 ports::NodeName name;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 104
101 NodeController::~NodeController() {} 105 NodeController::~NodeController() {}
102 106
103 NodeController::NodeController(Core* core) 107 NodeController::NodeController(Core* core)
104 : core_(core), 108 : core_(core),
105 name_(GetRandomNodeName()), 109 name_(GetRandomNodeName()),
106 node_(new ports::Node(name_, this)) { 110 node_(new ports::Node(name_, this)) {
107 DVLOG(1) << "Initializing node " << name_; 111 DVLOG(1) << "Initializing node " << name_;
108 } 112 }
109 113
114 #if defined(OS_MACOSX) && !defined(OS_IOS)
115 void NodeController::CreateMachPortRelayIfNeeded(
116 base::PortProvider* port_provider) {
117 base::AutoLock lock(mach_port_relay_lock_);
118 #if DCHECK_IS_ON()
119 DCHECK(!mach_port_relay_ ||
120 mach_port_relay_->port_provider() == port_provider);
121 #endif
122 mach_port_relay_.reset(new MachPortRelay(port_provider));
123 }
124 #endif
125
110 void NodeController::SetIOTaskRunner( 126 void NodeController::SetIOTaskRunner(
111 scoped_refptr<base::TaskRunner> task_runner) { 127 scoped_refptr<base::TaskRunner> task_runner) {
112 io_task_runner_ = task_runner; 128 io_task_runner_ = task_runner;
113 ThreadDestructionObserver::Create( 129 ThreadDestructionObserver::Create(
114 io_task_runner_, 130 io_task_runner_,
115 base::Bind(&NodeController::DropAllPeers, base::Unretained(this))); 131 base::Bind(&NodeController::DropAllPeers, base::Unretained(this)));
116 } 132 }
117 133
118 void NodeController::ConnectToChild(base::ProcessHandle process_handle, 134 void NodeController::ConnectToChild(base::ProcessHandle process_handle,
119 ScopedPlatformHandle platform_handle) { 135 ScopedPlatformHandle platform_handle) {
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 channel->SetRemoteProcessHandle(process_handle); 274 channel->SetRemoteProcessHandle(process_handle);
259 channel->Start(); 275 channel->Start();
260 276
261 channel->AcceptChild(name_, token); 277 channel->AcceptChild(name_, token);
262 } 278 }
263 279
264 void NodeController::ConnectToParentOnIOThread( 280 void NodeController::ConnectToParentOnIOThread(
265 ScopedPlatformHandle platform_handle) { 281 ScopedPlatformHandle platform_handle) {
266 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); 282 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
267 283
268 base::AutoLock lock(parent_lock_); 284 {
269 DCHECK(parent_name_ == ports::kInvalidNodeName); 285 base::AutoLock lock(parent_lock_);
286 DCHECK(parent_name_ == ports::kInvalidNodeName);
270 287
271 // At this point we don't know the parent's name, so we can't yet insert it 288 // At this point we don't know the parent's name, so we can't yet insert it
272 // into our |peers_| map. That will happen as soon as we receive an 289 // into our |peers_| map. That will happen as soon as we receive an
273 // AcceptChild message from them. 290 // AcceptChild message from them.
274 bootstrap_parent_channel_ = 291 bootstrap_parent_channel_ =
275 NodeChannel::Create(this, std::move(platform_handle), io_task_runner_); 292 NodeChannel::Create(this, std::move(platform_handle), io_task_runner_);
293 }
276 bootstrap_parent_channel_->Start(); 294 bootstrap_parent_channel_->Start();
277 } 295 }
278 296
279 scoped_refptr<NodeChannel> NodeController::GetPeerChannel( 297 scoped_refptr<NodeChannel> NodeController::GetPeerChannel(
280 const ports::NodeName& name) { 298 const ports::NodeName& name) {
281 base::AutoLock lock(peers_lock_); 299 base::AutoLock lock(peers_lock_);
282 auto it = peers_.find(name); 300 auto it = peers_.find(name);
283 if (it == peers_.end()) 301 if (it == peers_.end())
284 return nullptr; 302 return nullptr;
285 return it->second; 303 return it->second;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 if (!peer || !peer->HasRemoteProcessHandle()) { 404 if (!peer || !peer->HasRemoteProcessHandle()) {
387 if (broker) { 405 if (broker) {
388 broker->RelayPortsMessage(name, std::move(channel_message)); 406 broker->RelayPortsMessage(name, std::move(channel_message));
389 } else { 407 } else {
390 base::AutoLock lock(broker_lock_); 408 base::AutoLock lock(broker_lock_);
391 pending_relay_messages_[name].emplace(std::move(channel_message)); 409 pending_relay_messages_[name].emplace(std::move(channel_message));
392 } 410 }
393 return; 411 return;
394 } 412 }
395 } 413 }
396 #endif 414 #elif defined(OS_MACOSX) && !defined(OS_IOS)
415 if (channel_message->has_mach_ports()) {
416 // Messages containing mach ports are always routed through the broker, even
417 // if the broker process is the intended recipient.
418 bool use_broker = false;
erikchen 2016/03/09 19:13:17 What happens if the message has mach ports but the
Anand Mistry (off Chromium) 2016/03/11 07:44:18 That's covered below. The child startup process is
419 {
420 base::AutoLock lock(parent_lock_);
421 use_broker = (bootstrap_parent_channel_ ||
422 parent_name_ != ports::kInvalidNodeName);
423 }
424 if (use_broker) {
425 scoped_refptr<NodeChannel> broker = GetBrokerChannel();
426 if (broker) {
427 broker->RelayPortsMessage(name, std::move(channel_message));
428 } else {
429 base::AutoLock lock(broker_lock_);
430 pending_relay_messages_[name].emplace(std::move(channel_message));
431 }
432 return;
433 }
434 }
435 #endif // defined(OS_WIN)
397 436
398 if (peer) { 437 if (peer) {
399 peer->PortsMessage(std::move(channel_message)); 438 peer->PortsMessage(std::move(channel_message));
400 return; 439 return;
401 } 440 }
402 441
403 // If we don't know who the peer is, queue the message for delivery. If this 442 // If we don't know who the peer is, queue the message for delivery. If this
404 // is the first message queued for the peer, we also ask the broker to 443 // is the first message queued for the peer, we also ask the broker to
405 // introduce us to them. 444 // introduce us to them.
406 445
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node, 675 void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node,
637 const ports::NodeName& client_name, 676 const ports::NodeName& client_name,
638 ScopedPlatformHandle broker_channel) { 677 ScopedPlatformHandle broker_channel) {
639 scoped_refptr<NodeChannel> client = GetPeerChannel(client_name); 678 scoped_refptr<NodeChannel> client = GetPeerChannel(client_name);
640 if (!client) { 679 if (!client) {
641 DLOG(ERROR) << "BrokerClientAdded for unknown child " << client_name; 680 DLOG(ERROR) << "BrokerClientAdded for unknown child " << client_name;
642 return; 681 return;
643 } 682 }
644 683
645 // This should have come from our own broker. 684 // This should have come from our own broker.
646 if(GetBrokerChannel() != GetPeerChannel(from_node)) { 685 if (GetBrokerChannel() != GetPeerChannel(from_node)) {
647 DLOG(ERROR) << "BrokerClientAdded from non-broker node " << from_node; 686 DLOG(ERROR) << "BrokerClientAdded from non-broker node " << from_node;
648 return; 687 return;
649 } 688 }
650 689
651 DVLOG(1) << "Child " << client_name << " accepted by broker " << from_node; 690 DVLOG(1) << "Child " << client_name << " accepted by broker " << from_node;
652 691
653 client->AcceptBrokerClient(from_node, std::move(broker_channel)); 692 client->AcceptBrokerClient(from_node, std::move(broker_channel));
654 } 693 }
655 694
656 void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node, 695 void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node,
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
704 743
705 // Feed the broker any pending children of our own. 744 // Feed the broker any pending children of our own.
706 while (!pending_broker_clients.empty()) { 745 while (!pending_broker_clients.empty()) {
707 const ports::NodeName& child_name = pending_broker_clients.front(); 746 const ports::NodeName& child_name = pending_broker_clients.front();
708 auto it = pending_children_.find(child_name); 747 auto it = pending_children_.find(child_name);
709 DCHECK(it != pending_children_.end()); 748 DCHECK(it != pending_children_.end());
710 broker->AddBrokerClient(child_name, it->second->CopyRemoteProcessHandle()); 749 broker->AddBrokerClient(child_name, it->second->CopyRemoteProcessHandle());
711 pending_broker_clients.pop(); 750 pending_broker_clients.pop();
712 } 751 }
713 752
714 #if defined(OS_WIN) 753 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
715 // Have the broker relay any messages we have waiting. 754 // Have the broker relay any messages we have waiting.
716 for (auto& entry : pending_relay_messages) { 755 for (auto& entry : pending_relay_messages) {
717 const ports::NodeName& destination = entry.first; 756 const ports::NodeName& destination = entry.first;
718 auto& message_queue = entry.second; 757 auto& message_queue = entry.second;
719 while (!message_queue.empty()) { 758 while (!message_queue.empty()) {
720 broker->RelayPortsMessage(destination, std::move(message_queue.front())); 759 broker->RelayPortsMessage(destination, std::move(message_queue.front()));
721 message_queue.pop(); 760 message_queue.pop();
722 } 761 }
723 } 762 }
724 #endif 763 #endif
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
814 return; 853 return;
815 } 854 }
816 855
817 scoped_refptr<NodeChannel> channel = 856 scoped_refptr<NodeChannel> channel =
818 NodeChannel::Create(this, std::move(channel_handle), io_task_runner_); 857 NodeChannel::Create(this, std::move(channel_handle), io_task_runner_);
819 858
820 DVLOG(1) << "Adding new peer " << name << " via parent introduction."; 859 DVLOG(1) << "Adding new peer " << name << " via parent introduction.";
821 AddPeer(name, channel, true /* start_channel */); 860 AddPeer(name, channel, true /* start_channel */);
822 } 861 }
823 862
824 #if defined(OS_WIN) 863 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
825 void NodeController::OnRelayPortsMessage(const ports::NodeName& from_node, 864 void NodeController::OnRelayPortsMessage(const ports::NodeName& from_node,
826 base::ProcessHandle from_process, 865 base::ProcessHandle from_process,
827 const ports::NodeName& destination, 866 const ports::NodeName& destination,
828 Channel::MessagePtr message) { 867 Channel::MessagePtr message) {
868 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
869
829 if (GetBrokerChannel()) { 870 if (GetBrokerChannel()) {
830 // Only the broker should be asked to relay a message. 871 // Only the broker should be asked to relay a message.
831 LOG(ERROR) << "Non-broker refusing to relay message."; 872 LOG(ERROR) << "Non-broker refusing to relay message.";
832 DropPeer(from_node); 873 DropPeer(from_node);
833 return; 874 return;
834 } 875 }
835 876
836 // The parent should always know which process this came from. 877 // The parent should always know which process this came from.
837 DCHECK(from_process != base::kNullProcessHandle); 878 DCHECK(from_process != base::kNullProcessHandle);
838 879
880 #if defined(OS_WIN)
839 // Rewrite the handles to this (the parent) process. If the message is 881 // Rewrite the handles to this (the parent) process. If the message is
840 // destined for another child process, the handles will be rewritten to that 882 // destined for another child process, the handles will be rewritten to that
841 // process before going out (see NodeChannel::WriteChannelMessage). 883 // process before going out (see NodeChannel::WriteChannelMessage).
842 // 884 //
843 // TODO: We could avoid double-duplication. 885 // TODO: We could avoid double-duplication.
844 if (!Channel::Message::RewriteHandles(from_process, 886 if (!Channel::Message::RewriteHandles(from_process,
845 base::GetCurrentProcessHandle(), 887 base::GetCurrentProcessHandle(),
846 message->handles(), 888 message->handles(),
847 message->num_handles())) { 889 message->num_handles())) {
848 DLOG(ERROR) << "Failed to relay one or more handles."; 890 DLOG(ERROR) << "Failed to relay one or more handles.";
849 } 891 }
892 #else
893 MachPortRelay* relay = GetMachPortRelay();
894 if (!relay) {
895 LOG(ERROR) << "Receiving mach ports without a port relay from "
896 << from_node << ". Dropping message.";
897 return;
898 }
899 if (!relay->ExtractPortRights(message.get(), from_process)) {
900 // NodeChannel should ensure that MachPortRelay is ready for the remote
901 // process. At this point, if the port extraction failed, either something
902 // went wrong in the mach stuff, or the remote process died.
903 LOG(ERROR) << "Error on receiving mach ports " << from_node
904 << ". Dropping message.";
905 return;
906 }
907 #endif // defined(OS_WIN)
850 908
851 if (destination == name_) { 909 if (destination == name_) {
852 // Great, we can deliver this message locally. 910 // Great, we can deliver this message locally.
853 OnPortsMessage(std::move(message)); 911 OnPortsMessage(std::move(message));
854 return; 912 return;
855 } 913 }
856 914
857 scoped_refptr<NodeChannel> peer = GetPeerChannel(destination); 915 scoped_refptr<NodeChannel> peer = GetPeerChannel(destination);
858 if (peer) 916 if (peer)
859 peer->PortsMessage(std::move(message)); 917 peer->PortsMessage(std::move(message));
860 else 918 else
861 DLOG(ERROR) << "Dropping relay message for unknown node " << destination; 919 DLOG(ERROR) << "Dropping relay message for unknown node " << destination;
862 } 920 }
863 #endif 921 #endif
864 922
865 void NodeController::OnChannelError(const ports::NodeName& from_node) { 923 void NodeController::OnChannelError(const ports::NodeName& from_node) {
866 if (io_task_runner_->RunsTasksOnCurrentThread()) { 924 if (io_task_runner_->RunsTasksOnCurrentThread()) {
867 DropPeer(from_node); 925 DropPeer(from_node);
868 } else { 926 } else {
869 io_task_runner_->PostTask( 927 io_task_runner_->PostTask(
870 FROM_HERE, 928 FROM_HERE,
871 base::Bind(&NodeController::DropPeer, base::Unretained(this), 929 base::Bind(&NodeController::DropPeer, base::Unretained(this),
872 from_node)); 930 from_node));
873 } 931 }
874 } 932 }
875 933
934 #if defined(OS_MACOSX) && !defined(OS_IOS)
935 MachPortRelay* NodeController::GetMachPortRelay() {
936 {
937 base::AutoLock lock(parent_lock_);
938 // Return null if we're not the root.
939 if (bootstrap_parent_channel_ || parent_name_ != ports::kInvalidNodeName)
940 return nullptr;
941 }
942
943 base::AutoLock lock(mach_port_relay_lock_);
944 return mach_port_relay_.get();
945 }
946 #endif
947
876 void NodeController::DestroyOnIOThreadShutdown() { 948 void NodeController::DestroyOnIOThreadShutdown() {
877 destroy_on_io_thread_shutdown_ = true; 949 destroy_on_io_thread_shutdown_ = true;
878 } 950 }
879 951
880 void NodeController::AttemptShutdownIfRequested() { 952 void NodeController::AttemptShutdownIfRequested() {
881 base::Closure callback; 953 base::Closure callback;
882 { 954 {
883 base::AutoLock lock(shutdown_lock_); 955 base::AutoLock lock(shutdown_lock_);
884 if (shutdown_callback_.is_null()) 956 if (shutdown_callback_.is_null())
885 return; 957 return;
886 if (!node_->CanShutdownCleanly(true /* allow_local_ports */)) { 958 if (!node_->CanShutdownCleanly(true /* allow_local_ports */)) {
887 DVLOG(2) << "Unable to cleanly shut down node " << name_ << "."; 959 DVLOG(2) << "Unable to cleanly shut down node " << name_ << ".";
888 return; 960 return;
889 } 961 }
890 callback = shutdown_callback_; 962 callback = shutdown_callback_;
891 shutdown_callback_.Reset(); 963 shutdown_callback_.Reset();
892 } 964 }
893 965
894 DCHECK(!callback.is_null()); 966 DCHECK(!callback.is_null());
895 967
896 callback.Run(); 968 callback.Run();
897 } 969 }
898 970
899 } // namespace edk 971 } // namespace edk
900 } // namespace mojo 972 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698