1 /* 2 * Copyright (C) 2015 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 #pragma once 18 19 #include <stdint.h> 20 21 #include <android-base/macros.h> 22 23 #include "adb.h" 24 25 // Class to send and receive shell protocol packets. 26 // 27 // To keep things simple and predictable, reads and writes block until an entire 28 // packet is complete. 29 // 30 // Example: read raw data from |fd| and send it in a packet. 31 // ShellProtocol* p = new ShellProtocol(protocol_fd); 32 // int len = adb_read(stdout_fd, p->data(), p->data_capacity()); 33 // packet->WritePacket(ShellProtocol::kIdStdout, len); 34 // 35 // Example: read a packet and print it to |stdout|. 36 // ShellProtocol* p = new ShellProtocol(protocol_fd); 37 // if (p->ReadPacket() && p->id() == kIdStdout) { 38 // fwrite(p->data(), 1, p->data_length(), stdout); 39 // } 40 class ShellProtocol { 41 public: 42 // This is an unscoped enum to make it easier to compare against raw bytes. 43 enum Id : uint8_t { 44 kIdStdin = 0, 45 kIdStdout = 1, 46 kIdStderr = 2, 47 kIdExit = 3, 48 49 // Close subprocess stdin if possible. 50 kIdCloseStdin = 4, 51 52 // Window size change (an ASCII version of struct winsize). 53 kIdWindowSizeChange = 5, 54 55 // Indicates an invalid or unknown packet. 56 kIdInvalid = 255, 57 }; 58 59 // ShellPackets will probably be too large to allocate on the stack so they 60 // should be dynamically allocated on the heap instead. 61 // 62 // |fd| is an open file descriptor to be used to send or receive packets. 63 explicit ShellProtocol(int fd); 64 virtual ~ShellProtocol(); 65 66 // Returns a pointer to the data buffer. data()67 const char* data() const { return buffer_ + kHeaderSize; } data()68 char* data() { return buffer_ + kHeaderSize; } 69 70 // Returns the total capacity of the data buffer. data_capacity()71 size_t data_capacity() const { return buffer_end_ - data(); } 72 73 // Reads a packet from the FD. 74 // 75 // If a packet is too big to fit in the buffer then Read() will split the 76 // packet across multiple calls. For example, reading a 50-byte packet into 77 // a 20-byte buffer would read 20 bytes, 20 bytes, then 10 bytes. 78 // 79 // Returns false if the FD closed or errored. 80 bool Read(); 81 82 // Returns the ID of the packet in the buffer. id()83 int id() const { return buffer_[0]; } 84 85 // Returns the number of bytes that have been read into the data buffer. data_length()86 size_t data_length() const { return data_length_; } 87 88 // Writes the packet currently in the buffer to the FD. 89 // 90 // Returns false if the FD closed or errored. 91 bool Write(Id id, size_t length); 92 93 private: 94 // Packets support 4-byte lengths. 95 typedef uint32_t length_t; 96 97 enum { 98 // It's OK if MAX_PAYLOAD doesn't match on the sending and receiving 99 // end, reading will split larger packets into multiple smaller ones. 100 kBufferSize = MAX_PAYLOAD, 101 102 // Header is 1 byte ID + 4 bytes length. 103 kHeaderSize = sizeof(Id) + sizeof(length_t) 104 }; 105 106 int fd_; 107 char buffer_[kBufferSize]; 108 size_t data_length_ = 0, bytes_left_ = 0; 109 110 // We need to be able to modify this value for testing purposes, but it 111 // will stay constant during actual program use. 112 char* buffer_end_ = buffer_ + sizeof(buffer_); 113 114 friend class ShellProtocolTest; 115 116 DISALLOW_COPY_AND_ASSIGN(ShellProtocol); 117 }; 118