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