Home | History | Annotate | Download | only in ipc
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef SRC_IPC_BUFFERED_FRAME_DESERIALIZER_H_
     18 #define SRC_IPC_BUFFERED_FRAME_DESERIALIZER_H_
     19 
     20 #include <stddef.h>
     21 
     22 #include <list>
     23 #include <memory>
     24 
     25 #include <sys/mman.h>
     26 
     27 #include "perfetto/base/paged_memory.h"
     28 #include "perfetto/base/utils.h"
     29 #include "perfetto/ipc/basic_types.h"
     30 
     31 namespace perfetto {
     32 namespace ipc {
     33 
     34 class Frame;  // Defined in the protobuf autogenerated wire_protocol.pb.h.
     35 
     36 // Deserializes incoming frames, taking care of buffering and tokenization.
     37 // Used by both host and client to decode incoming frames.
     38 //
     39 // Which problem does it solve?
     40 // ----------------------------
     41 // The wire protocol is as follows:
     42 // [32-bit frame size][proto-encoded Frame], e.g:
     43 // [06 00 00 00][00 11 22 33 44 55 66]
     44 // [02 00 00 00][AA BB]
     45 // [04 00 00 00][CC DD EE FF]
     46 // However, given that the socket works in SOCK_STREAM mode, the recv() calls
     47 // might see the following:
     48 // 06 00 00
     49 // 00 00 11 22 33 44 55
     50 // 66 02 00 00 00 ...
     51 // This class takes care of buffering efficiently the data received, without
     52 // making any assumption on how the incoming data will be chunked by the socket.
     53 // For instance, it is possible that a recv() doesn't produce any frame (because
     54 // it received only a part of the frame) or produces more than one frame.
     55 //
     56 // Usage
     57 // -----
     58 // Both host and client use this as follows:
     59 //
     60 // auto buf = rpc_frame_decoder.BeginReceive();
     61 // size_t rsize = socket.recv(buf.first, buf.second);
     62 // rpc_frame_decoder.EndReceive(rsize);
     63 // while (Frame frame = rpc_frame_decoder.PopNextFrame()) {
     64 //   ... process |frame|
     65 // }
     66 //
     67 // Design goals:
     68 // -------------
     69 // - Optimize for the realistic case of each recv() receiving one or more
     70 //   whole frames. In this case no memmove is performed.
     71 // - Guarantee that frames lay in a virtually contiguous memory area.
     72 //   This allows to use the protobuf-lite deserialization API (scattered
     73 //   deserialization is supported only by libprotobuf-full).
     74 // - Put a hard boundary to the size of the incoming buffer. This is to prevent
     75 //   that a malicious sends an abnormally large frame and OOMs us.
     76 // - Simplicity: just use a linear mmap region. No reallocations or scattering.
     77 //   Takes care of madvise()-ing unused memory.
     78 
     79 class BufferedFrameDeserializer {
     80  public:
     81   struct ReceiveBuffer {
     82     char* data;
     83     size_t size;
     84   };
     85 
     86   // |max_capacity| is overridable only for tests.
     87   explicit BufferedFrameDeserializer(size_t max_capacity = kIPCBufferSize);
     88   ~BufferedFrameDeserializer();
     89 
     90   // This function doesn't really belong here as it does Serialization, unlike
     91   // the rest of this class. However it is so small and has so many dependencies
     92   // in common that doesn't justify having its own class.
     93   static std::string Serialize(const Frame&);
     94 
     95   // Returns a buffer that can be passed to recv(). The buffer is deliberately
     96   // not initialized.
     97   ReceiveBuffer BeginReceive();
     98 
     99   // Must be called soon after BeginReceive().
    100   // |recv_size| is the number of valid bytes that have been written into the
    101   // buffer previously returned by BeginReceive() (the return value of recv()).
    102   // Returns false if a header > |max_capacity| is received, in which case the
    103   // caller is expected to shutdown the socket and terminate the ipc.
    104   bool EndReceive(size_t recv_size) PERFETTO_WARN_UNUSED_RESULT;
    105 
    106   // Decodes and returns the next decoded frame in the buffer if any, nullptr
    107   // if no further frames have been decoded.
    108   std::unique_ptr<Frame> PopNextFrame();
    109 
    110   size_t capacity() const { return capacity_; }
    111   size_t size() const { return size_; }
    112 
    113  private:
    114   BufferedFrameDeserializer(const BufferedFrameDeserializer&) = delete;
    115   BufferedFrameDeserializer& operator=(const BufferedFrameDeserializer&) =
    116       delete;
    117 
    118   // If a valid frame is decoded it is added to |decoded_frames_|.
    119   void DecodeFrame(const char*, size_t);
    120 
    121   char* buf() { return reinterpret_cast<char*>(buf_.Get()); }
    122 
    123   base::PagedMemory buf_;
    124   const size_t capacity_ = 0;  // sizeof(|buf_|).
    125 
    126   // THe number of bytes in |buf_| that contain valid data (as a result of
    127   // EndReceive()). This is always <= |capacity_|.
    128   size_t size_ = 0;
    129 
    130   std::list<std::unique_ptr<Frame>> decoded_frames_;
    131 };
    132 
    133 }  // namespace ipc
    134 }  // namespace perfetto
    135 
    136 #endif  // SRC_IPC_BUFFERED_FRAME_DESERIALIZER_H_
    137