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

Side by Side Diff: third_party/mojo/src/mojo/edk/system/channel.cc

Issue 1311043003: Update mojo sdk to rev c02a28868825edfa57ab77947b8cb15e741c5598 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/channel.h" 5 #include "mojo/edk/system/channel.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 21 matching lines...) Expand all
32 : platform_support_(platform_support), 32 : platform_support_(platform_support),
33 is_running_(false), 33 is_running_(false),
34 is_shutting_down_(false), 34 is_shutting_down_(false),
35 channel_manager_(nullptr) { 35 channel_manager_(nullptr) {
36 } 36 }
37 37
38 void Channel::Init(scoped_ptr<RawChannel> raw_channel) { 38 void Channel::Init(scoped_ptr<RawChannel> raw_channel) {
39 DCHECK(creation_thread_checker_.CalledOnValidThread()); 39 DCHECK(creation_thread_checker_.CalledOnValidThread());
40 DCHECK(raw_channel); 40 DCHECK(raw_channel);
41 41
42 // No need to take |lock_|, since this must be called before this object 42 // No need to take |mutex_|, since this must be called before this object
43 // becomes thread-safe. 43 // becomes thread-safe.
44 DCHECK(!is_running_); 44 DCHECK(!is_running_);
45 raw_channel_ = raw_channel.Pass(); 45 raw_channel_ = raw_channel.Pass();
46 raw_channel_->Init(this); 46 raw_channel_->Init(this);
47 is_running_ = true; 47 is_running_ = true;
48 } 48 }
49 49
50 void Channel::SetChannelManager(ChannelManager* channel_manager) { 50 void Channel::SetChannelManager(ChannelManager* channel_manager) {
51 DCHECK(channel_manager); 51 DCHECK(channel_manager);
52 52
53 base::AutoLock locker(lock_); 53 MutexLocker locker(&mutex_);
54 DCHECK(!is_shutting_down_); 54 DCHECK(!is_shutting_down_);
55 DCHECK(!channel_manager_); 55 DCHECK(!channel_manager_);
56 channel_manager_ = channel_manager; 56 channel_manager_ = channel_manager;
57 } 57 }
58 58
59 void Channel::Shutdown() { 59 void Channel::Shutdown() {
60 DCHECK(creation_thread_checker_.CalledOnValidThread()); 60 DCHECK(creation_thread_checker_.CalledOnValidThread());
61 61
62 IdToEndpointMap to_destroy; 62 IdToEndpointMap to_destroy;
63 { 63 {
64 base::AutoLock locker(lock_); 64 MutexLocker locker(&mutex_);
65 if (!is_running_) 65 if (!is_running_)
66 return; 66 return;
67 67
68 // Note: Don't reset |raw_channel_|, in case we're being called from within 68 // Note: Don't reset |raw_channel_|, in case we're being called from within
69 // |OnReadMessage()| or |OnError()|. 69 // |OnReadMessage()| or |OnError()|.
70 raw_channel_->Shutdown(); 70 raw_channel_->Shutdown();
71 is_running_ = false; 71 is_running_ = false;
72 72
73 // We need to deal with it outside the lock. 73 // We need to deal with it outside the lock.
74 std::swap(to_destroy, local_id_to_endpoint_map_); 74 std::swap(to_destroy, local_id_to_endpoint_map_);
75 } 75 }
76 76
77 size_t num_live = 0; 77 size_t num_live = 0;
78 size_t num_zombies = 0; 78 size_t num_zombies = 0;
79 for (IdToEndpointMap::iterator it = to_destroy.begin(); 79 for (IdToEndpointMap::iterator it = to_destroy.begin();
80 it != to_destroy.end(); ++it) { 80 it != to_destroy.end(); ++it) {
81 if (it->second) { 81 if (it->second) {
82 num_live++; 82 num_live++;
83 it->second->DetachFromChannel(); 83 it->second->DetachFromChannel();
84 } else { 84 } else {
85 num_zombies++; 85 num_zombies++;
86 } 86 }
87 } 87 }
88 DVLOG_IF(2, num_live || num_zombies) << "Shut down Channel with " << num_live 88 DVLOG_IF(2, num_live || num_zombies) << "Shut down Channel with " << num_live
89 << " live endpoints and " << num_zombies 89 << " live endpoints and " << num_zombies
90 << " zombies"; 90 << " zombies";
91 } 91 }
92 92
93 void Channel::WillShutdownSoon() { 93 void Channel::WillShutdownSoon() {
94 base::AutoLock locker(lock_); 94 MutexLocker locker(&mutex_);
95 is_shutting_down_ = true; 95 is_shutting_down_ = true;
96 channel_manager_ = nullptr; 96 channel_manager_ = nullptr;
97 } 97 }
98 98
99 void Channel::SetBootstrapEndpoint(scoped_refptr<ChannelEndpoint> endpoint) { 99 void Channel::SetBootstrapEndpoint(scoped_refptr<ChannelEndpoint> endpoint) {
100 // Used for both local and remote IDs. 100 // Used for both local and remote IDs.
101 ChannelEndpointId bootstrap_id = ChannelEndpointId::GetBootstrap(); 101 ChannelEndpointId bootstrap_id = ChannelEndpointId::GetBootstrap();
102 SetBootstrapEndpointWithIds(endpoint.Pass(), bootstrap_id, bootstrap_id); 102 SetBootstrapEndpointWithIds(endpoint.Pass(), bootstrap_id, bootstrap_id);
103 } 103 }
104 104
105 void Channel::SetBootstrapEndpointWithIds( 105 void Channel::SetBootstrapEndpointWithIds(
106 scoped_refptr<ChannelEndpoint> endpoint, 106 scoped_refptr<ChannelEndpoint> endpoint,
107 ChannelEndpointId local_id, 107 ChannelEndpointId local_id,
108 ChannelEndpointId remote_id) { 108 ChannelEndpointId remote_id) {
109 DCHECK(endpoint); 109 DCHECK(endpoint);
110 110
111 { 111 {
112 base::AutoLock locker(lock_); 112 MutexLocker locker(&mutex_);
113 113
114 DLOG_IF(WARNING, is_shutting_down_) 114 DLOG_IF(WARNING, is_shutting_down_)
115 << "SetBootstrapEndpoint() while shutting down"; 115 << "SetBootstrapEndpoint() while shutting down";
116 116
117 // There must not be an endpoint with that ID already. 117 // There must not be an endpoint with that ID already.
118 DCHECK(local_id_to_endpoint_map_.find(local_id) == 118 DCHECK(local_id_to_endpoint_map_.find(local_id) ==
119 local_id_to_endpoint_map_.end()); 119 local_id_to_endpoint_map_.end());
120 120
121 local_id_to_endpoint_map_[local_id] = endpoint; 121 local_id_to_endpoint_map_[local_id] = endpoint;
122 } 122 }
123 123
124 endpoint->AttachAndRun(this, local_id, remote_id); 124 endpoint->AttachAndRun(this, local_id, remote_id);
125 } 125 }
126 126
127 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { 127 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) {
128 base::AutoLock locker(lock_); 128 MutexLocker locker(&mutex_);
129 if (!is_running_) { 129 if (!is_running_) {
130 // TODO(vtl): I think this is probably not an error condition, but I should 130 // TODO(vtl): I think this is probably not an error condition, but I should
131 // think about it (and the shutdown sequence) more carefully. 131 // think about it (and the shutdown sequence) more carefully.
132 LOG(WARNING) << "WriteMessage() after shutdown"; 132 LOG(WARNING) << "WriteMessage() after shutdown";
133 return false; 133 return false;
134 } 134 }
135 135
136 DLOG_IF(WARNING, is_shutting_down_) << "WriteMessage() while shutting down"; 136 DLOG_IF(WARNING, is_shutting_down_) << "WriteMessage() while shutting down";
137 return raw_channel_->WriteMessage(message.Pass()); 137 return raw_channel_->WriteMessage(message.Pass());
138 } 138 }
139 139
140 bool Channel::IsWriteBufferEmpty() { 140 bool Channel::IsWriteBufferEmpty() {
141 base::AutoLock locker(lock_); 141 MutexLocker locker(&mutex_);
142 if (!is_running_) 142 if (!is_running_)
143 return true; 143 return true;
144 return raw_channel_->IsWriteBufferEmpty(); 144 return raw_channel_->IsWriteBufferEmpty();
145 } 145 }
146 146
147 void Channel::DetachEndpoint(ChannelEndpoint* endpoint, 147 void Channel::DetachEndpoint(ChannelEndpoint* endpoint,
148 ChannelEndpointId local_id, 148 ChannelEndpointId local_id,
149 ChannelEndpointId remote_id) { 149 ChannelEndpointId remote_id) {
150 DCHECK(endpoint); 150 DCHECK(endpoint);
151 DCHECK(local_id.is_valid()); 151 DCHECK(local_id.is_valid());
152 152
153 if (!remote_id.is_valid()) 153 if (!remote_id.is_valid())
154 return; // Nothing to do. 154 return; // Nothing to do.
155 155
156 { 156 {
157 base::AutoLock locker_(lock_); 157 MutexLocker locker_(&mutex_);
158 if (!is_running_) 158 if (!is_running_)
159 return; 159 return;
160 160
161 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); 161 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id);
162 // We detach immediately if we receive a remove message, so it's possible 162 // We detach immediately if we receive a remove message, so it's possible
163 // that the local ID is no longer in |local_id_to_endpoint_map_|, or even 163 // that the local ID is no longer in |local_id_to_endpoint_map_|, or even
164 // that it's since been reused for another endpoint. In both cases, there's 164 // that it's since been reused for another endpoint. In both cases, there's
165 // nothing more to do. 165 // nothing more to do.
166 if (it == local_id_to_endpoint_map_.end() || it->second.get() != endpoint) 166 if (it == local_id_to_endpoint_map_.end() || it->second.get() != endpoint)
167 return; 167 return;
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 240
241 scoped_refptr<IncomingEndpoint> Channel::DeserializeEndpoint( 241 scoped_refptr<IncomingEndpoint> Channel::DeserializeEndpoint(
242 const void* source) { 242 const void* source) {
243 const SerializedEndpoint* s = static_cast<const SerializedEndpoint*>(source); 243 const SerializedEndpoint* s = static_cast<const SerializedEndpoint*>(source);
244 ChannelEndpointId local_id = s->receiver_endpoint_id; 244 ChannelEndpointId local_id = s->receiver_endpoint_id;
245 // No need to check the validity of |local_id| -- if it's not valid, it simply 245 // No need to check the validity of |local_id| -- if it's not valid, it simply
246 // won't be in |incoming_endpoints_|. 246 // won't be in |incoming_endpoints_|.
247 DVLOG_IF(2, !local_id.is_valid() || !local_id.is_remote()) 247 DVLOG_IF(2, !local_id.is_valid() || !local_id.is_remote())
248 << "Attempt to get incoming endpoint for invalid ID " << local_id; 248 << "Attempt to get incoming endpoint for invalid ID " << local_id;
249 249
250 base::AutoLock locker(lock_); 250 MutexLocker locker(&mutex_);
251 251
252 auto it = incoming_endpoints_.find(local_id); 252 auto it = incoming_endpoints_.find(local_id);
253 if (it == incoming_endpoints_.end()) { 253 if (it == incoming_endpoints_.end()) {
254 LOG(ERROR) << "Failed to deserialize endpoint (ID = " << local_id << ")"; 254 LOG(ERROR) << "Failed to deserialize endpoint (ID = " << local_id << ")";
255 return nullptr; 255 return nullptr;
256 } 256 }
257 257
258 DVLOG(2) << "Deserializing endpoint (new local ID = " << local_id << ")"; 258 DVLOG(2) << "Deserializing endpoint (new local ID = " << local_id << ")";
259 259
260 scoped_refptr<IncomingEndpoint> rv; 260 scoped_refptr<IncomingEndpoint> rv;
261 rv.swap(it->second); 261 rv.swap(it->second);
262 incoming_endpoints_.erase(it); 262 incoming_endpoints_.erase(it);
263 return rv; 263 return rv;
264 } 264 }
265 265
266 size_t Channel::GetSerializedPlatformHandleSize() const { 266 size_t Channel::GetSerializedPlatformHandleSize() const {
267 // TODO(vtl): Having to lock |mutex_| here is a bit unfortunate. Maybe we
268 // should get the size in |Init()| and cache it?
269 MutexLocker locker(&mutex_);
267 return raw_channel_->GetSerializedPlatformHandleSize(); 270 return raw_channel_->GetSerializedPlatformHandleSize();
268 } 271 }
269 272
270 Channel::~Channel() { 273 Channel::~Channel() {
271 // The channel should have been shut down first. 274 // The channel should have been shut down first.
272 DCHECK(!is_running_); 275 DCHECK(!is_running_);
273 } 276 }
274 277
275 void Channel::OnReadMessage( 278 void Channel::OnReadMessage(
276 const MessageInTransit::View& message_view, 279 const MessageInTransit::View& message_view,
(...skipping 19 matching lines...) Expand all
296 299
297 void Channel::OnError(Error error) { 300 void Channel::OnError(Error error) {
298 DCHECK(creation_thread_checker_.CalledOnValidThread()); 301 DCHECK(creation_thread_checker_.CalledOnValidThread());
299 302
300 switch (error) { 303 switch (error) {
301 case ERROR_READ_SHUTDOWN: 304 case ERROR_READ_SHUTDOWN:
302 // The other side was cleanly closed, so this isn't actually an error. 305 // The other side was cleanly closed, so this isn't actually an error.
303 DVLOG(1) << "RawChannel read error (shutdown)"; 306 DVLOG(1) << "RawChannel read error (shutdown)";
304 break; 307 break;
305 case ERROR_READ_BROKEN: { 308 case ERROR_READ_BROKEN: {
306 base::AutoLock locker(lock_); 309 MutexLocker locker(&mutex_);
307 LOG_IF(ERROR, !is_shutting_down_) 310 LOG_IF(ERROR, !is_shutting_down_)
308 << "RawChannel read error (connection broken)"; 311 << "RawChannel read error (connection broken)";
309 break; 312 break;
310 } 313 }
311 case ERROR_READ_BAD_MESSAGE: 314 case ERROR_READ_BAD_MESSAGE:
312 // Receiving a bad message means either a bug, data corruption, or 315 // Receiving a bad message means either a bug, data corruption, or
313 // malicious attack (probably due to some other bug). 316 // malicious attack (probably due to some other bug).
314 LOG(ERROR) << "RawChannel read error (received bad message)"; 317 LOG(ERROR) << "RawChannel read error (received bad message)";
315 break; 318 break;
316 case ERROR_READ_UNKNOWN: 319 case ERROR_READ_UNKNOWN:
(...skipping 16 matching lines...) Expand all
333 message_view.type() == MessageInTransit::Type::ENDPOINT); 336 message_view.type() == MessageInTransit::Type::ENDPOINT);
334 337
335 ChannelEndpointId local_id = message_view.destination_id(); 338 ChannelEndpointId local_id = message_view.destination_id();
336 if (!local_id.is_valid()) { 339 if (!local_id.is_valid()) {
337 HandleRemoteError("Received message with no destination ID"); 340 HandleRemoteError("Received message with no destination ID");
338 return; 341 return;
339 } 342 }
340 343
341 scoped_refptr<ChannelEndpoint> endpoint; 344 scoped_refptr<ChannelEndpoint> endpoint;
342 { 345 {
343 base::AutoLock locker(lock_); 346 MutexLocker locker(&mutex_);
344 347
345 // Since we own |raw_channel_|, and this method and |Shutdown()| should only 348 // Since we own |raw_channel_|, and this method and |Shutdown()| should only
346 // be called from the creation thread, |raw_channel_| should never be null 349 // be called from the creation thread, |raw_channel_| should never be null
347 // here. 350 // here.
348 DCHECK(is_running_); 351 DCHECK(is_running_);
349 352
350 IdToEndpointMap::const_iterator it = 353 IdToEndpointMap::const_iterator it =
351 local_id_to_endpoint_map_.find(local_id); 354 local_id_to_endpoint_map_.find(local_id);
352 if (it != local_id_to_endpoint_map_.end()) { 355 if (it != local_id_to_endpoint_map_.end()) {
353 // Ignore messages for zombie endpoints (not an error). 356 // Ignore messages for zombie endpoints (not an error).
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 return false; 455 return false;
453 } 456 }
454 457
455 // Create/initialize an |IncomingEndpoint| and thus an endpoint (outside the 458 // Create/initialize an |IncomingEndpoint| and thus an endpoint (outside the
456 // lock). 459 // lock).
457 scoped_refptr<IncomingEndpoint> incoming_endpoint(new IncomingEndpoint()); 460 scoped_refptr<IncomingEndpoint> incoming_endpoint(new IncomingEndpoint());
458 scoped_refptr<ChannelEndpoint> endpoint = incoming_endpoint->Init(); 461 scoped_refptr<ChannelEndpoint> endpoint = incoming_endpoint->Init();
459 462
460 bool success = true; 463 bool success = true;
461 { 464 {
462 base::AutoLock locker(lock_); 465 MutexLocker locker(&mutex_);
463 466
464 if (local_id_to_endpoint_map_.find(local_id) == 467 if (local_id_to_endpoint_map_.find(local_id) ==
465 local_id_to_endpoint_map_.end()) { 468 local_id_to_endpoint_map_.end()) {
466 DCHECK(incoming_endpoints_.find(local_id) == incoming_endpoints_.end()); 469 DCHECK(incoming_endpoints_.find(local_id) == incoming_endpoints_.end());
467 470
468 // TODO(vtl): Use emplace when we move to C++11 unordered_maps. (It'll 471 // TODO(vtl): Use emplace when we move to C++11 unordered_maps. (It'll
469 // avoid some refcount churn.) 472 // avoid some refcount churn.)
470 local_id_to_endpoint_map_[local_id] = endpoint; 473 local_id_to_endpoint_map_[local_id] = endpoint;
471 incoming_endpoints_[local_id] = incoming_endpoint; 474 incoming_endpoints_[local_id] = incoming_endpoint;
472 } else { 475 } else {
(...skipping 10 matching lines...) Expand all
483 endpoint->AttachAndRun(this, local_id, remote_id); 486 endpoint->AttachAndRun(this, local_id, remote_id);
484 return true; 487 return true;
485 } 488 }
486 489
487 bool Channel::OnRemoveEndpoint(ChannelEndpointId local_id, 490 bool Channel::OnRemoveEndpoint(ChannelEndpointId local_id,
488 ChannelEndpointId remote_id) { 491 ChannelEndpointId remote_id) {
489 DCHECK(creation_thread_checker_.CalledOnValidThread()); 492 DCHECK(creation_thread_checker_.CalledOnValidThread());
490 493
491 scoped_refptr<ChannelEndpoint> endpoint; 494 scoped_refptr<ChannelEndpoint> endpoint;
492 { 495 {
493 base::AutoLock locker(lock_); 496 MutexLocker locker(&mutex_);
494 497
495 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); 498 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id);
496 if (it == local_id_to_endpoint_map_.end()) { 499 if (it == local_id_to_endpoint_map_.end()) {
497 DVLOG(2) << "Remove endpoint error: not found"; 500 DVLOG(2) << "Remove endpoint error: not found";
498 return false; 501 return false;
499 } 502 }
500 503
501 if (!it->second) { 504 if (!it->second) {
502 // Remove messages "crossed"; we have to wait for the ack. 505 // Remove messages "crossed"; we have to wait for the ack.
503 return true; 506 return true;
(...skipping 15 matching lines...) Expand all
519 static_cast<unsigned>(local_id.value()), 522 static_cast<unsigned>(local_id.value()),
520 static_cast<unsigned>(remote_id.value())).c_str()); 523 static_cast<unsigned>(remote_id.value())).c_str());
521 } 524 }
522 525
523 return true; 526 return true;
524 } 527 }
525 528
526 bool Channel::OnRemoveEndpointAck(ChannelEndpointId local_id) { 529 bool Channel::OnRemoveEndpointAck(ChannelEndpointId local_id) {
527 DCHECK(creation_thread_checker_.CalledOnValidThread()); 530 DCHECK(creation_thread_checker_.CalledOnValidThread());
528 531
529 base::AutoLock locker(lock_); 532 MutexLocker locker(&mutex_);
530 533
531 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); 534 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id);
532 if (it == local_id_to_endpoint_map_.end()) { 535 if (it == local_id_to_endpoint_map_.end()) {
533 DVLOG(2) << "Remove endpoint ack error: not found"; 536 DVLOG(2) << "Remove endpoint ack error: not found";
534 return false; 537 return false;
535 } 538 }
536 539
537 if (it->second) { 540 if (it->second) {
538 DVLOG(2) << "Remove endpoint ack error: wrong state"; 541 DVLOG(2) << "Remove endpoint ack error: wrong state";
539 return false; 542 return false;
(...skipping 22 matching lines...) Expand all
562 // keeps the endpoint alive even after the lock is released. Otherwise, there's 565 // keeps the endpoint alive even after the lock is released. Otherwise, there's
563 // the temptation to simply pass the result of |new ChannelEndpoint(...)| 566 // the temptation to simply pass the result of |new ChannelEndpoint(...)|
564 // directly to this function, which wouldn't be sufficient for safety. 567 // directly to this function, which wouldn't be sufficient for safety.
565 ChannelEndpointId Channel::AttachAndRunEndpoint( 568 ChannelEndpointId Channel::AttachAndRunEndpoint(
566 scoped_refptr<ChannelEndpoint> endpoint) { 569 scoped_refptr<ChannelEndpoint> endpoint) {
567 DCHECK(endpoint); 570 DCHECK(endpoint);
568 571
569 ChannelEndpointId local_id; 572 ChannelEndpointId local_id;
570 ChannelEndpointId remote_id; 573 ChannelEndpointId remote_id;
571 { 574 {
572 base::AutoLock locker(lock_); 575 MutexLocker locker(&mutex_);
573 576
574 DLOG_IF(WARNING, is_shutting_down_) 577 DLOG_IF(WARNING, is_shutting_down_)
575 << "AttachAndRunEndpoint() while shutting down"; 578 << "AttachAndRunEndpoint() while shutting down";
576 579
577 do { 580 do {
578 local_id = local_id_generator_.GetNext(); 581 local_id = local_id_generator_.GetNext();
579 } while (local_id_to_endpoint_map_.find(local_id) != 582 } while (local_id_to_endpoint_map_.find(local_id) !=
580 local_id_to_endpoint_map_.end()); 583 local_id_to_endpoint_map_.end());
581 584
582 // TODO(vtl): We also need to check for collisions of remote IDs here. 585 // TODO(vtl): We also need to check for collisions of remote IDs here.
(...skipping 24 matching lines...) Expand all
607 << ", local ID " << local_id << ", remote ID " << remote_id; 610 << ", local ID " << local_id << ", remote ID " << remote_id;
608 scoped_ptr<MessageInTransit> message(new MessageInTransit( 611 scoped_ptr<MessageInTransit> message(new MessageInTransit(
609 MessageInTransit::Type::CHANNEL, subtype, 0, nullptr)); 612 MessageInTransit::Type::CHANNEL, subtype, 0, nullptr));
610 message->set_source_id(local_id); 613 message->set_source_id(local_id);
611 message->set_destination_id(remote_id); 614 message->set_destination_id(remote_id);
612 return WriteMessage(message.Pass()); 615 return WriteMessage(message.Pass());
613 } 616 }
614 617
615 } // namespace system 618 } // namespace system
616 } // namespace mojo 619 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698