Home | History | Annotate | Download | only in adb_connection_maintainer
      1 /*
      2  * Copyright (C) 2018 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 #include <iomanip>
     17 #include <sstream>
     18 #include <string>
     19 #include <memory>
     20 #include <glog/logging.h>
     21 
     22 #include <unistd.h>
     23 
     24 #include "common/libs/fs/shared_fd.h"
     25 #include "host/libs/adb_connection_maintainer/adb_connection_maintainer.h"
     26 
     27 namespace {
     28 
     29 std::string MakeMessage(const std::string& user_message) {
     30   static constexpr char kPrefix[] = "host:";
     31   static constexpr std::size_t kPrefixLen = sizeof kPrefix - 1;
     32   std::ostringstream ss;
     33   ss << std::setfill('0') << std::setw(4) << std::hex
     34      << (kPrefixLen + user_message.size()) << kPrefix << user_message;
     35   return ss.str();
     36 }
     37 
     38 std::string MakeIPAndPort(int port) {
     39   static constexpr char kLocalHostPrefix[] = "127.0.0.1:";
     40   return kLocalHostPrefix + std::to_string(port);
     41 }
     42 
     43 std::string MakeConnectMessage(int port) {
     44   static constexpr char kConnectPrefix[] = "connect:";
     45   return MakeMessage(kConnectPrefix + MakeIPAndPort(port));
     46 }
     47 
     48 // returns true if successfully sent the whole message
     49 bool SendAll(cvd::SharedFD sock, const std::string& msg) {
     50   ssize_t total_written{};
     51   while (total_written < static_cast<ssize_t>(msg.size())) {
     52     if (!sock->IsOpen()) {
     53       return false;
     54     }
     55     auto just_written = sock->Send(msg.c_str() + total_written,
     56                                    msg.size() - total_written, MSG_NOSIGNAL);
     57     if (just_written <= 0) {
     58       return false;
     59     }
     60     total_written += just_written;
     61   }
     62   return true;
     63 }
     64 
     65 std::string RecvAll(cvd::SharedFD sock, const size_t count) {
     66   size_t total_read{};
     67   std::unique_ptr<char[]> data(new char[count]);
     68   while (total_read < count) {
     69     auto just_read = sock->Read(data.get() + total_read, count - total_read);
     70     if (just_read <= 0) {
     71       return {};
     72     }
     73     total_read += just_read;
     74   }
     75   return {data.get(), count};
     76 }
     77 
     78 // Response will either be OKAY or FAIL
     79 constexpr char kAdbOkayStatusResponse[] = "OKAY";
     80 constexpr std::size_t kAdbStatusResponseLength =
     81     sizeof kAdbOkayStatusResponse - 1;
     82 // adb sends the length of what is to follow as a 4 characters string of hex
     83 // digits
     84 constexpr std::size_t kAdbMessageLengthLength = 4;
     85 
     86 constexpr int kAdbDaemonPort = 5037;
     87 
     88 bool AdbConnect(cvd::SharedFD sock, int port) {
     89   if (!SendAll(sock, MakeConnectMessage(port))) {
     90     return false;
     91   }
     92   return RecvAll(sock, kAdbStatusResponseLength) == kAdbOkayStatusResponse;
     93 }
     94 
     95 // assumes the OKAY/FAIL status has already been read
     96 std::string RecvAdbResponse(cvd::SharedFD sock) {
     97   auto length_as_hex_str = RecvAll(sock, kAdbMessageLengthLength);
     98   auto length = std::stoi(length_as_hex_str, nullptr, 16);
     99   return RecvAll(sock, length);
    100 }
    101 
    102 void EstablishConnection(int port) {
    103   while (true) {
    104     LOG(INFO) << "Attempting to connect to device on port " << port;
    105     auto sock = cvd::SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
    106     if (sock->IsOpen() && AdbConnect(sock, port)) {
    107       LOG(INFO) << "connection attempted to device on port " << port;
    108       break;
    109     }
    110     sleep(2);
    111   }
    112 }
    113 
    114 void WaitForAdbDisconnection(int port) {
    115   LOG(INFO) << "Watching for disconnect on port " << port;
    116   while (true) {
    117     auto sock = cvd::SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
    118     if (!SendAll(sock, MakeMessage("devices"))) {
    119       break;
    120     }
    121     if (RecvAll(sock, 4) != kAdbOkayStatusResponse) {
    122       break;
    123     }
    124     auto devices_str = RecvAdbResponse(sock);
    125     if (devices_str.find(MakeIPAndPort(port)) == std::string::npos) {
    126       break;
    127     }
    128     sleep(2);
    129   }
    130 }
    131 
    132 }  // namespace
    133 
    134 [[noreturn]] void cvd::EstablishAndMaintainConnection(int port) {
    135   while (true) {
    136     EstablishConnection(port);
    137     WaitForAdbDisconnection(port);
    138   }
    139 }
    140