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