Home | History | Annotate | Download | only in system
      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
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/edk/system/channel.h"
      6 
      7 #include <string.h>
      8 
      9 #include <algorithm>
     10 #include <limits>
     11 #include <utility>
     12 
     13 #include "base/macros.h"
     14 #include "base/memory/aligned_memory.h"
     15 #include "base/process/process_handle.h"
     16 #include "mojo/edk/embedder/platform_handle.h"
     17 
     18 #if defined(OS_MACOSX) && !defined(OS_IOS)
     19 #include "base/mac/mach_logging.h"
     20 #elif defined(OS_WIN)
     21 #include "base/win/win_util.h"
     22 #endif
     23 
     24 namespace mojo {
     25 namespace edk {
     26 
     27 namespace {
     28 
     29 static_assert(sizeof(Channel::Message::Header) % kChannelMessageAlignment == 0,
     30     "Invalid Header size.");
     31 
     32 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
     33 static_assert(sizeof(Channel::Message::Header) == 8,
     34               "Header must be 8 bytes on ChromeOS and Android");
     35 #endif
     36 
     37 }  // namespace
     38 
     39 const size_t kReadBufferSize = 4096;
     40 const size_t kMaxUnusedReadBufferCapacity = 64 * 1024;
     41 const size_t kMaxChannelMessageSize = 256 * 1024 * 1024;
     42 const size_t kMaxAttachedHandles = 128;
     43 
     44 Channel::Message::Message(size_t payload_size,
     45                           size_t max_handles,
     46                           Header::MessageType message_type)
     47     : max_handles_(max_handles) {
     48   DCHECK_LE(max_handles_, kMaxAttachedHandles);
     49 
     50   size_t extra_header_size = 0;
     51 #if defined(OS_WIN)
     52   // On Windows we serialize HANDLEs into the extra header space.
     53   extra_header_size = max_handles_ * sizeof(HandleEntry);
     54 #elif defined(OS_MACOSX) && !defined(OS_IOS)
     55   // On OSX, some of the platform handles may be mach ports, which are
     56   // serialised into the message buffer. Since there could be a mix of fds and
     57   // mach ports, we store the mach ports as an <index, port> pair (of uint32_t),
     58   // so that the original ordering of handles can be re-created.
     59   if (max_handles) {
     60     extra_header_size =
     61         sizeof(MachPortsExtraHeader) + (max_handles * sizeof(MachPortsEntry));
     62   }
     63 #endif
     64   // Pad extra header data to be aliged to |kChannelMessageAlignment| bytes.
     65   if (extra_header_size % kChannelMessageAlignment) {
     66     extra_header_size += kChannelMessageAlignment -
     67                          (extra_header_size % kChannelMessageAlignment);
     68   }
     69   DCHECK_EQ(0u, extra_header_size % kChannelMessageAlignment);
     70 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
     71   DCHECK_EQ(0u, extra_header_size);
     72 #endif
     73 
     74   size_ = sizeof(Header) + extra_header_size + payload_size;
     75   data_ = static_cast<char*>(base::AlignedAlloc(size_,
     76                                                 kChannelMessageAlignment));
     77   // Only zero out the header and not the payload. Since the payload is going to
     78   // be memcpy'd, zeroing the payload is unnecessary work and a significant
     79   // performance issue when dealing with large messages. Any sanitizer errors
     80   // complaining about an uninitialized read in the payload area should be
     81   // treated as an error and fixed.
     82   memset(data_, 0, sizeof(Header) + extra_header_size);
     83   header_ = reinterpret_cast<Header*>(data_);
     84 
     85   DCHECK_LE(size_, std::numeric_limits<uint32_t>::max());
     86   header_->num_bytes = static_cast<uint32_t>(size_);
     87 
     88   DCHECK_LE(sizeof(Header) + extra_header_size,
     89             std::numeric_limits<uint16_t>::max());
     90   header_->message_type = message_type;
     91 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
     92   header_->num_handles = static_cast<uint16_t>(max_handles);
     93 #else
     94   header_->num_header_bytes =
     95       static_cast<uint16_t>(sizeof(Header) + extra_header_size);
     96 #endif
     97 
     98   if (max_handles_ > 0) {
     99 #if defined(OS_WIN)
    100     handles_ = reinterpret_cast<HandleEntry*>(mutable_extra_header());
    101     // Initialize all handles to invalid values.
    102     for (size_t i = 0; i < max_handles_; ++i)
    103       handles_[i].handle = base::win::HandleToUint32(INVALID_HANDLE_VALUE);
    104 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    105     mach_ports_header_ =
    106         reinterpret_cast<MachPortsExtraHeader*>(mutable_extra_header());
    107     mach_ports_header_->num_ports = 0;
    108     // Initialize all handles to invalid values.
    109     for (size_t i = 0; i < max_handles_; ++i) {
    110       mach_ports_header_->entries[i] =
    111           {0, static_cast<uint32_t>(MACH_PORT_NULL)};
    112     }
    113 #endif
    114   }
    115 }
    116 
    117 Channel::Message::~Message() {
    118   base::AlignedFree(data_);
    119 }
    120 
    121 // static
    122 Channel::MessagePtr Channel::Message::Deserialize(const void* data,
    123                                                   size_t data_num_bytes) {
    124   if (data_num_bytes < sizeof(Header))
    125     return nullptr;
    126 
    127   const Header* header = reinterpret_cast<const Header*>(data);
    128   if (header->num_bytes != data_num_bytes) {
    129     DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes
    130                 << " != " << data_num_bytes;
    131     return nullptr;
    132   }
    133 
    134 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
    135   size_t payload_size = data_num_bytes - sizeof(Header);
    136   const char* payload = static_cast<const char*>(data) + sizeof(Header);
    137 #else
    138   if (header->num_bytes < header->num_header_bytes ||
    139       header->num_header_bytes < sizeof(Header)) {
    140     DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < "
    141                 << header->num_header_bytes;
    142     return nullptr;
    143   }
    144 
    145   uint32_t extra_header_size = header->num_header_bytes - sizeof(Header);
    146   size_t payload_size = data_num_bytes - header->num_header_bytes;
    147   const char* payload =
    148       static_cast<const char*>(data) + header->num_header_bytes;
    149 #endif  // defined(MOJO_EDK_LEGACY_PROTOCOL)
    150 
    151 #if defined(OS_WIN)
    152   uint32_t max_handles = extra_header_size / sizeof(HandleEntry);
    153 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    154   if (extra_header_size < sizeof(MachPortsExtraHeader)) {
    155     DLOG(ERROR) << "Decoding invalid message: " << extra_header_size << " < "
    156                 << sizeof(MachPortsExtraHeader);
    157     return nullptr;
    158   }
    159   uint32_t max_handles = (extra_header_size - sizeof(MachPortsExtraHeader)) /
    160       sizeof(MachPortsEntry);
    161 #else
    162   const uint32_t max_handles = 0;
    163 #endif  // defined(OS_WIN)
    164 
    165   if (header->num_handles > max_handles || max_handles > kMaxAttachedHandles) {
    166     DLOG(ERROR) << "Decoding invalid message:" << header->num_handles
    167                 << " > " << max_handles;
    168     return nullptr;
    169   }
    170 
    171   MessagePtr message(new Message(payload_size, max_handles));
    172   DCHECK_EQ(message->data_num_bytes(), data_num_bytes);
    173 
    174   // Copy all payload bytes.
    175   if (payload_size)
    176     memcpy(message->mutable_payload(), payload, payload_size);
    177 
    178 #if !defined(MOJO_EDK_LEGACY_PROTOCOL)
    179   DCHECK_EQ(message->extra_header_size(), extra_header_size);
    180   DCHECK_EQ(message->header_->num_header_bytes, header->num_header_bytes);
    181 
    182   if (message->extra_header_size()) {
    183     // Copy extra header bytes.
    184     memcpy(message->mutable_extra_header(),
    185            static_cast<const char*>(data) + sizeof(Header),
    186            message->extra_header_size());
    187   }
    188 #endif
    189 
    190   message->header_->num_handles = header->num_handles;
    191 #if defined(OS_WIN)
    192   ScopedPlatformHandleVectorPtr handles(
    193       new PlatformHandleVector(header->num_handles));
    194   for (size_t i = 0; i < header->num_handles; i++) {
    195     (*handles)[i].handle = reinterpret_cast<HANDLE>(
    196         static_cast<uintptr_t>(message->handles_[i].handle));
    197   }
    198   message->SetHandles(std::move(handles));
    199 #endif
    200 
    201   return message;
    202 }
    203 
    204 size_t Channel::Message::payload_size() const {
    205 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
    206   return header_->num_bytes - sizeof(Header);
    207 #else
    208   return size_ - header_->num_header_bytes;
    209 #endif
    210 }
    211 
    212 #if defined(OS_MACOSX) && !defined(OS_IOS)
    213 bool Channel::Message::has_mach_ports() const {
    214   if (!has_handles())
    215     return false;
    216 
    217   for (const auto& handle : (*handle_vector_)) {
    218     if (handle.type == PlatformHandle::Type::MACH ||
    219         handle.type == PlatformHandle::Type::MACH_NAME) {
    220       return true;
    221     }
    222   }
    223   return false;
    224 }
    225 #endif
    226 
    227 void Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) {
    228 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
    229   // Old semantics for ChromeOS and Android
    230   if (header_->num_handles == 0) {
    231     CHECK(!new_handles || new_handles->size() == 0);
    232     return;
    233   }
    234   CHECK(new_handles && new_handles->size() == header_->num_handles);
    235   std::swap(handle_vector_, new_handles);
    236 
    237 #else
    238   if (max_handles_ == 0) {
    239     CHECK(!new_handles || new_handles->size() == 0);
    240     return;
    241   }
    242 
    243   CHECK(new_handles && new_handles->size() <= max_handles_);
    244   header_->num_handles = static_cast<uint16_t>(new_handles->size());
    245   std::swap(handle_vector_, new_handles);
    246 #if defined(OS_WIN)
    247   memset(handles_, 0, extra_header_size());
    248   for (size_t i = 0; i < handle_vector_->size(); i++)
    249     handles_[i].handle = base::win::HandleToUint32((*handle_vector_)[i].handle);
    250 #endif  // defined(OS_WIN)
    251 #endif  // defined(MOJO_EDK_LEGACY_PROTOCOL)
    252 
    253 #if defined(OS_MACOSX) && !defined(OS_IOS)
    254   size_t mach_port_index = 0;
    255   if (mach_ports_header_) {
    256     for (size_t i = 0; i < max_handles_; ++i) {
    257       mach_ports_header_->entries[i] =
    258           {0, static_cast<uint32_t>(MACH_PORT_NULL)};
    259     }
    260     for (size_t i = 0; i < handle_vector_->size(); i++) {
    261       if ((*handle_vector_)[i].type == PlatformHandle::Type::MACH ||
    262           (*handle_vector_)[i].type == PlatformHandle::Type::MACH_NAME) {
    263         mach_port_t port = (*handle_vector_)[i].port;
    264         mach_ports_header_->entries[mach_port_index].index = i;
    265         mach_ports_header_->entries[mach_port_index].mach_port = port;
    266         mach_port_index++;
    267       }
    268     }
    269     mach_ports_header_->num_ports = static_cast<uint16_t>(mach_port_index);
    270   }
    271 #endif
    272 }
    273 
    274 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() {
    275 #if defined(OS_MACOSX) && !defined(OS_IOS)
    276   if (mach_ports_header_) {
    277     for (size_t i = 0; i < max_handles_; ++i) {
    278       mach_ports_header_->entries[i] =
    279           {0, static_cast<uint32_t>(MACH_PORT_NULL)};
    280     }
    281     mach_ports_header_->num_ports = 0;
    282   }
    283   header_->num_handles = 0;
    284   return std::move(handle_vector_);
    285 #else
    286   header_->num_handles = 0;
    287   return std::move(handle_vector_);
    288 #endif
    289 }
    290 
    291 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandlesForTransport() {
    292 #if defined(OS_WIN)
    293   // Not necessary on Windows.
    294   NOTREACHED();
    295   return nullptr;
    296 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    297   if (handle_vector_) {
    298     for (auto it = handle_vector_->begin(); it != handle_vector_->end(); ) {
    299       if (it->type == PlatformHandle::Type::MACH ||
    300           it->type == PlatformHandle::Type::MACH_NAME) {
    301         // For Mach port names, we can can just leak them. They're not real
    302         // ports anyways. For real ports, they're leaked because this is a child
    303         // process and the remote process will take ownership.
    304         it = handle_vector_->erase(it);
    305       } else {
    306         ++it;
    307       }
    308     }
    309   }
    310   return std::move(handle_vector_);
    311 #else
    312   return std::move(handle_vector_);
    313 #endif
    314 }
    315 
    316 #if defined(OS_WIN)
    317 // static
    318 bool Channel::Message::RewriteHandles(base::ProcessHandle from_process,
    319                                       base::ProcessHandle to_process,
    320                                       PlatformHandleVector* handles) {
    321   bool success = true;
    322   for (size_t i = 0; i < handles->size(); ++i) {
    323     if (!(*handles)[i].is_valid()) {
    324       DLOG(ERROR) << "Refusing to duplicate invalid handle.";
    325       continue;
    326     }
    327     DCHECK_EQ((*handles)[i].owning_process, from_process);
    328     BOOL result = DuplicateHandle(
    329         from_process, (*handles)[i].handle, to_process,
    330         &(*handles)[i].handle, 0, FALSE,
    331         DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
    332     if (result) {
    333       (*handles)[i].owning_process = to_process;
    334     } else {
    335       success = false;
    336 
    337       // If handle duplication fails, the source handle will already be closed
    338       // due to DUPLICATE_CLOSE_SOURCE. Replace the handle in the message with
    339       // an invalid handle.
    340       (*handles)[i].handle = INVALID_HANDLE_VALUE;
    341       (*handles)[i].owning_process = base::GetCurrentProcessHandle();
    342     }
    343   }
    344   return success;
    345 }
    346 #endif
    347 
    348 // Helper class for managing a Channel's read buffer allocations. This maintains
    349 // a single contiguous buffer with the layout:
    350 //
    351 //   [discarded bytes][occupied bytes][unoccupied bytes]
    352 //
    353 // The Reserve() method ensures that a certain capacity of unoccupied bytes are
    354 // available. It does not claim that capacity and only allocates new capacity
    355 // when strictly necessary.
    356 //
    357 // Claim() marks unoccupied bytes as occupied.
    358 //
    359 // Discard() marks occupied bytes as discarded, signifying that their contents
    360 // can be forgotten or overwritten.
    361 //
    362 // Realign() moves occupied bytes to the front of the buffer so that those
    363 // occupied bytes are properly aligned.
    364 //
    365 // The most common Channel behavior in practice should result in very few
    366 // allocations and copies, as memory is claimed and discarded shortly after
    367 // being reserved, and future reservations will immediately reuse discarded
    368 // memory.
    369 class Channel::ReadBuffer {
    370  public:
    371   ReadBuffer() {
    372     size_ = kReadBufferSize;
    373     data_ = static_cast<char*>(base::AlignedAlloc(size_,
    374                                                   kChannelMessageAlignment));
    375   }
    376 
    377   ~ReadBuffer() {
    378     DCHECK(data_);
    379     base::AlignedFree(data_);
    380   }
    381 
    382   const char* occupied_bytes() const { return data_ + num_discarded_bytes_; }
    383 
    384   size_t num_occupied_bytes() const {
    385     return num_occupied_bytes_ - num_discarded_bytes_;
    386   }
    387 
    388   // Ensures the ReadBuffer has enough contiguous space allocated to hold
    389   // |num_bytes| more bytes; returns the address of the first available byte.
    390   char* Reserve(size_t num_bytes) {
    391     if (num_occupied_bytes_ + num_bytes > size_) {
    392       size_ = std::max(size_ * 2, num_occupied_bytes_ + num_bytes);
    393       void* new_data = base::AlignedAlloc(size_, kChannelMessageAlignment);
    394       memcpy(new_data, data_, num_occupied_bytes_);
    395       base::AlignedFree(data_);
    396       data_ = static_cast<char*>(new_data);
    397     }
    398 
    399     return data_ + num_occupied_bytes_;
    400   }
    401 
    402   // Marks the first |num_bytes| unoccupied bytes as occupied.
    403   void Claim(size_t num_bytes) {
    404     DCHECK_LE(num_occupied_bytes_ + num_bytes, size_);
    405     num_occupied_bytes_ += num_bytes;
    406   }
    407 
    408   // Marks the first |num_bytes| occupied bytes as discarded. This may result in
    409   // shrinkage of the internal buffer, and it is not safe to assume the result
    410   // of a previous Reserve() call is still valid after this.
    411   void Discard(size_t num_bytes) {
    412     DCHECK_LE(num_discarded_bytes_ + num_bytes, num_occupied_bytes_);
    413     num_discarded_bytes_ += num_bytes;
    414 
    415     if (num_discarded_bytes_ == num_occupied_bytes_) {
    416       // We can just reuse the buffer from the beginning in this common case.
    417       num_discarded_bytes_ = 0;
    418       num_occupied_bytes_ = 0;
    419     }
    420 
    421     if (num_discarded_bytes_ > kMaxUnusedReadBufferCapacity) {
    422       // In the uncommon case that we have a lot of discarded data at the
    423       // front of the buffer, simply move remaining data to a smaller buffer.
    424       size_t num_preserved_bytes = num_occupied_bytes_ - num_discarded_bytes_;
    425       size_ = std::max(num_preserved_bytes, kReadBufferSize);
    426       char* new_data = static_cast<char*>(
    427           base::AlignedAlloc(size_, kChannelMessageAlignment));
    428       memcpy(new_data, data_ + num_discarded_bytes_, num_preserved_bytes);
    429       base::AlignedFree(data_);
    430       data_ = new_data;
    431       num_discarded_bytes_ = 0;
    432       num_occupied_bytes_ = num_preserved_bytes;
    433     }
    434 
    435     if (num_occupied_bytes_ == 0 && size_ > kMaxUnusedReadBufferCapacity) {
    436       // Opportunistically shrink the read buffer back down to a small size if
    437       // it's grown very large. We only do this if there are no remaining
    438       // unconsumed bytes in the buffer to avoid copies in most the common
    439       // cases.
    440       size_ = kMaxUnusedReadBufferCapacity;
    441       base::AlignedFree(data_);
    442       data_ = static_cast<char*>(
    443           base::AlignedAlloc(size_, kChannelMessageAlignment));
    444     }
    445   }
    446 
    447   void Realign() {
    448     size_t num_bytes = num_occupied_bytes();
    449     memmove(data_, occupied_bytes(), num_bytes);
    450     num_discarded_bytes_ = 0;
    451     num_occupied_bytes_ = num_bytes;
    452   }
    453 
    454  private:
    455   char* data_ = nullptr;
    456 
    457   // The total size of the allocated buffer.
    458   size_t size_ = 0;
    459 
    460   // The number of discarded bytes at the beginning of the allocated buffer.
    461   size_t num_discarded_bytes_ = 0;
    462 
    463   // The total number of occupied bytes, including discarded bytes.
    464   size_t num_occupied_bytes_ = 0;
    465 
    466   DISALLOW_COPY_AND_ASSIGN(ReadBuffer);
    467 };
    468 
    469 Channel::Channel(Delegate* delegate)
    470     : delegate_(delegate), read_buffer_(new ReadBuffer) {
    471 }
    472 
    473 Channel::~Channel() {
    474 }
    475 
    476 void Channel::ShutDown() {
    477   delegate_ = nullptr;
    478   ShutDownImpl();
    479 }
    480 
    481 char* Channel::GetReadBuffer(size_t *buffer_capacity) {
    482   DCHECK(read_buffer_);
    483   size_t required_capacity = *buffer_capacity;
    484   if (!required_capacity)
    485     required_capacity = kReadBufferSize;
    486 
    487   *buffer_capacity = required_capacity;
    488   return read_buffer_->Reserve(required_capacity);
    489 }
    490 
    491 bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
    492   bool did_dispatch_message = false;
    493   read_buffer_->Claim(bytes_read);
    494   while (read_buffer_->num_occupied_bytes() >= sizeof(Message::Header)) {
    495     // Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could
    496     // happen on architectures that don't allow misaligned words access (i.e.
    497     // anything other than x86). Only re-align when necessary to avoid copies.
    498     if (reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()) %
    499         kChannelMessageAlignment != 0)
    500       read_buffer_->Realign();
    501 
    502     // We have at least enough data available for a MessageHeader.
    503     const Message::Header* header = reinterpret_cast<const Message::Header*>(
    504         read_buffer_->occupied_bytes());
    505     if (header->num_bytes < sizeof(Message::Header) ||
    506         header->num_bytes > kMaxChannelMessageSize) {
    507       LOG(ERROR) << "Invalid message size: " << header->num_bytes;
    508       return false;
    509     }
    510 
    511     if (read_buffer_->num_occupied_bytes() < header->num_bytes) {
    512       // Not enough data available to read the full message. Hint to the
    513       // implementation that it should try reading the full size of the message.
    514       *next_read_size_hint =
    515           header->num_bytes - read_buffer_->num_occupied_bytes();
    516       return true;
    517     }
    518 
    519 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
    520     size_t extra_header_size = 0;
    521     const void* extra_header = nullptr;
    522     size_t payload_size = header->num_bytes - sizeof(Message::Header);
    523     void* payload = payload_size ? const_cast<Message::Header*>(&header[1])
    524                                  : nullptr;
    525 #else
    526     if (header->num_header_bytes < sizeof(Message::Header) ||
    527         header->num_header_bytes > header->num_bytes) {
    528       LOG(ERROR) << "Invalid message header size: " << header->num_header_bytes;
    529       return false;
    530     }
    531     size_t extra_header_size =
    532         header->num_header_bytes - sizeof(Message::Header);
    533     const void* extra_header = extra_header_size ? header + 1 : nullptr;
    534     size_t payload_size = header->num_bytes - header->num_header_bytes;
    535     void* payload =
    536         payload_size ? reinterpret_cast<Message::Header*>(
    537                            const_cast<char*>(read_buffer_->occupied_bytes()) +
    538                            header->num_header_bytes)
    539                      : nullptr;
    540 #endif  // defined(MOJO_EDK_LEGACY_PROTOCOL)
    541 
    542     ScopedPlatformHandleVectorPtr handles;
    543     if (header->num_handles > 0) {
    544       if (!GetReadPlatformHandles(header->num_handles, extra_header,
    545                                  extra_header_size, &handles)) {
    546         return false;
    547       }
    548 
    549       if (!handles) {
    550         // Not enough handles available for this message.
    551         break;
    552       }
    553     }
    554 
    555     // We've got a complete message! Dispatch it and try another.
    556     if (header->message_type != Message::Header::MessageType::NORMAL) {
    557       if (!OnControlMessage(header->message_type, payload, payload_size,
    558                             std::move(handles))) {
    559         return false;
    560       }
    561       did_dispatch_message = true;
    562     } else if (delegate_) {
    563       delegate_->OnChannelMessage(payload, payload_size, std::move(handles));
    564       did_dispatch_message = true;
    565     }
    566 
    567     read_buffer_->Discard(header->num_bytes);
    568   }
    569 
    570   *next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize;
    571   return true;
    572 }
    573 
    574 void Channel::OnError() {
    575   if (delegate_)
    576     delegate_->OnChannelError();
    577 }
    578 
    579 bool Channel::OnControlMessage(Message::Header::MessageType message_type,
    580                                const void* payload,
    581                                size_t payload_size,
    582                                ScopedPlatformHandleVectorPtr handles) {
    583   return false;
    584 }
    585 
    586 }  // namespace edk
    587 }  // namespace mojo
    588