Home | History | Annotate | Download | only in adb
      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 // This file contains classes and functionality to launch shell subprocesses
     18 // in adbd and communicate between those subprocesses and the adb client.
     19 //
     20 // The main features exposed here are:
     21 //   1. A ShellPacket class to wrap data in a simple protocol. Both adbd and
     22 //      the adb client use this class to transmit data between them.
     23 //   2. Functions to launch a subprocess on the adbd side.
     24 
     25 #ifndef SHELL_SERVICE_H_
     26 #define SHELL_SERVICE_H_
     27 
     28 #include <stdint.h>
     29 
     30 #include <android-base/macros.h>
     31 
     32 #include "adb.h"
     33 
     34 // Class to send and receive shell protocol packets.
     35 //
     36 // To keep things simple and predictable, reads and writes block until an entire
     37 // packet is complete.
     38 //
     39 // Example: read raw data from |fd| and send it in a packet.
     40 //   ShellProtocol* p = new ShellProtocol(protocol_fd);
     41 //   int len = adb_read(stdout_fd, p->data(), p->data_capacity());
     42 //   packet->WritePacket(ShellProtocol::kIdStdout, len);
     43 //
     44 // Example: read a packet and print it to |stdout|.
     45 //   ShellProtocol* p = new ShellProtocol(protocol_fd);
     46 //   if (p->ReadPacket() && p->id() == kIdStdout) {
     47 //       fwrite(p->data(), 1, p->data_length(), stdout);
     48 //   }
     49 class ShellProtocol {
     50   public:
     51     // This is an unscoped enum to make it easier to compare against raw bytes.
     52     enum Id : uint8_t {
     53         kIdStdin = 0,
     54         kIdStdout = 1,
     55         kIdStderr = 2,
     56         kIdExit = 3,
     57 
     58         // Close subprocess stdin if possible.
     59         kIdCloseStdin = 4,
     60 
     61         // Window size change (an ASCII version of struct winsize).
     62         kIdWindowSizeChange = 5,
     63 
     64         // Indicates an invalid or unknown packet.
     65         kIdInvalid = 255,
     66     };
     67 
     68     // ShellPackets will probably be too large to allocate on the stack so they
     69     // should be dynamically allocated on the heap instead.
     70     //
     71     // |fd| is an open file descriptor to be used to send or receive packets.
     72     explicit ShellProtocol(int fd);
     73     virtual ~ShellProtocol();
     74 
     75     // Returns a pointer to the data buffer.
     76     const char* data() const { return buffer_ + kHeaderSize; }
     77     char* data() { return buffer_ + kHeaderSize; }
     78 
     79     // Returns the total capacity of the data buffer.
     80     size_t data_capacity() const { return buffer_end_ - data(); }
     81 
     82     // Reads a packet from the FD.
     83     //
     84     // If a packet is too big to fit in the buffer then Read() will split the
     85     // packet across multiple calls. For example, reading a 50-byte packet into
     86     // a 20-byte buffer would read 20 bytes, 20 bytes, then 10 bytes.
     87     //
     88     // Returns false if the FD closed or errored.
     89     bool Read();
     90 
     91     // Returns the ID of the packet in the buffer.
     92     int id() const { return buffer_[0]; }
     93 
     94     // Returns the number of bytes that have been read into the data buffer.
     95     size_t data_length() const { return data_length_; }
     96 
     97     // Writes the packet currently in the buffer to the FD.
     98     //
     99     // Returns false if the FD closed or errored.
    100     bool Write(Id id, size_t length);
    101 
    102   private:
    103     // Packets support 4-byte lengths.
    104     typedef uint32_t length_t;
    105 
    106     enum {
    107         // It's OK if MAX_PAYLOAD doesn't match on the sending and receiving
    108         // end, reading will split larger packets into multiple smaller ones.
    109         kBufferSize = MAX_PAYLOAD,
    110 
    111         // Header is 1 byte ID + 4 bytes length.
    112         kHeaderSize = sizeof(Id) + sizeof(length_t)
    113     };
    114 
    115     int fd_;
    116     char buffer_[kBufferSize];
    117     size_t data_length_ = 0, bytes_left_ = 0;
    118 
    119     // We need to be able to modify this value for testing purposes, but it
    120     // will stay constant during actual program use.
    121     char* buffer_end_ = buffer_ + sizeof(buffer_);
    122 
    123     friend class ShellProtocolTest;
    124 
    125     DISALLOW_COPY_AND_ASSIGN(ShellProtocol);
    126 };
    127 
    128 #if !ADB_HOST
    129 
    130 enum class SubprocessType {
    131     kPty,
    132     kRaw,
    133 };
    134 
    135 enum class SubprocessProtocol {
    136     kNone,
    137     kShell,
    138 };
    139 
    140 // Forks and starts a new shell subprocess. If |name| is empty an interactive
    141 // shell is started, otherwise |name| is executed non-interactively.
    142 //
    143 // Returns an open FD connected to the subprocess or -1 on failure.
    144 int StartSubprocess(const char* name, const char* terminal_type,
    145                     SubprocessType type, SubprocessProtocol protocol);
    146 
    147 #endif  // !ADB_HOST
    148 
    149 #endif  // SHELL_SERVICE_H_
    150