• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "host/frontend/adb_connector/adb_connection_maintainer.h"
17 
18 #include <cctype>
19 #include <iomanip>
20 #include <sstream>
21 #include <string>
22 #include <memory>
23 #include <vector>
24 #include <android-base/logging.h>
25 
26 #include <unistd.h>
27 
28 #include "common/libs/fs/shared_buf.h"
29 #include "common/libs/fs/shared_fd.h"
30 
31 namespace cuttlefish {
32 namespace {
33 
MakeMessage(const std::string & user_message)34 std::string MakeMessage(const std::string& user_message) {
35   std::ostringstream ss;
36   ss << std::setfill('0') << std::setw(4) << std::hex << user_message.size()
37      << user_message;
38   return ss.str();
39 }
40 
MakeShellUptimeMessage()41 std::string MakeShellUptimeMessage() {
42   return MakeMessage("shell,raw:cut -d. -f1 /proc/uptime");
43 }
44 
MakeTransportMessage(const std::string & address)45 std::string MakeTransportMessage(const std::string& address) {
46   return MakeMessage("host:transport:" + address);
47 }
48 
MakeConnectMessage(const std::string & address)49 std::string MakeConnectMessage(const std::string& address) {
50   return MakeMessage("host:connect:" + address);
51 }
52 
MakeDisconnectMessage(const std::string & address)53 std::string MakeDisconnectMessage(const std::string& address) {
54   return MakeMessage("host:disconnect:" + address);
55 }
56 
57 // Response will either be OKAY or FAIL
58 constexpr char kAdbOkayStatusResponse[] = "OKAY";
59 constexpr std::size_t kAdbStatusResponseLength =
60     sizeof kAdbOkayStatusResponse - 1;
61 // adb sends the length of what is to follow as a 4 characters string of hex
62 // digits
63 constexpr std::size_t kAdbMessageLengthLength = 4;
64 
65 constexpr int kAdbDaemonPort = 5037;
66 
AdbSendMessage(const SharedFD & sock,const std::string & message)67 bool AdbSendMessage(const SharedFD& sock, const std::string& message) {
68   if (!sock->IsOpen()) {
69     return false;
70   }
71   if (!SendAll(sock, message)) {
72     LOG(WARNING) << "failed to send all bytes to adb daemon";
73     return false;
74   }
75   return RecvAll(sock, kAdbStatusResponseLength) == kAdbOkayStatusResponse;
76 }
77 
AdbSendMessage(const std::string & message)78 bool AdbSendMessage(const std::string& message) {
79   auto sock = SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
80   return AdbSendMessage(sock, message);
81 }
82 
AdbConnect(const std::string & address)83 bool AdbConnect(const std::string& address) {
84   return AdbSendMessage(MakeConnectMessage(address));
85 }
86 
AdbDisconnect(const std::string & address)87 bool AdbDisconnect(const std::string& address) {
88   return AdbSendMessage(MakeDisconnectMessage(address));
89 }
90 
IsInteger(const std::string & str)91 bool IsInteger(const std::string& str) {
92   return !str.empty() && std::all_of(str.begin(), str.end(),
93                                      [](char c) { return std::isdigit(c); });
94 }
95 
96 // assumes the OKAY/FAIL status has already been read
RecvAdbResponse(const SharedFD & sock)97 std::string RecvAdbResponse(const SharedFD& sock) {
98   auto length_as_hex_str = RecvAll(sock, kAdbMessageLengthLength);
99   if (!IsInteger(length_as_hex_str)) {
100     return {};
101   }
102   auto length = std::stoi(length_as_hex_str, nullptr, 16);
103   return RecvAll(sock, length);
104 }
105 
106 // Returns a negative value if uptime result couldn't be read for
107 // any reason.
RecvUptimeResult(const SharedFD & sock)108 int RecvUptimeResult(const SharedFD& sock) {
109   std::vector<char> uptime_vec{};
110   std::vector<char> just_read(16);
111   do {
112     auto count = sock->Read(just_read.data(), just_read.size());
113     if (count < 0) {
114       LOG(WARNING) << "couldn't receive adb shell output";
115       return -1;
116     }
117     just_read.resize(count);
118     uptime_vec.insert(uptime_vec.end(), just_read.begin(), just_read.end());
119   } while (!just_read.empty());
120 
121   if (uptime_vec.empty()) {
122     LOG(WARNING) << "empty adb shell result";
123     return -1;
124   }
125 
126   uptime_vec.pop_back();
127 
128   auto uptime_str = std::string{uptime_vec.data(), uptime_vec.size()};
129   if (!IsInteger(uptime_str)) {
130     LOG(WARNING) << "non-numeric: uptime result: " << uptime_str;
131     return -1;
132   }
133 
134   return std::stoi(uptime_str);
135 }
136 
137 // There needs to be a gap between the adb commands, the daemon isn't able to
138 // handle the avalanche of requests we would be sending without a sleep. Five
139 // seconds is much larger than seems necessary so we should be more than okay.
140 static constexpr int kAdbCommandGapTime = 5;
141 
EstablishConnection(const std::string & address)142 void EstablishConnection(const std::string& address) {
143   LOG(DEBUG) << "Attempting to connect to device with address " << address;
144   while (!AdbConnect(address)) {
145     sleep(kAdbCommandGapTime);
146   }
147   LOG(DEBUG) << "adb connect message for " << address << " successfully sent";
148   sleep(kAdbCommandGapTime);
149 }
150 
WaitForAdbDisconnection(const std::string & address)151 void WaitForAdbDisconnection(const std::string& address) {
152   // adb daemon doesn't seem to handle quick, successive messages well. The
153   // sleeps stabilize the communication.
154   LOG(DEBUG) << "Watching for disconnect on " << address;
155   while (true) {
156     auto sock = SharedFD::SocketLocalClient(kAdbDaemonPort, SOCK_STREAM);
157     if (!AdbSendMessage(sock, MakeTransportMessage(address))) {
158       LOG(WARNING) << "transport message failed, response body: "
159                    << RecvAdbResponse(sock);
160       break;
161     }
162     if (!AdbSendMessage(sock, MakeShellUptimeMessage())) {
163       LOG(WARNING) << "adb shell uptime message failed";
164       break;
165     }
166 
167     auto uptime = RecvUptimeResult(sock);
168     if (uptime < 0) {
169       LOG(WARNING) << "couldn't read uptime result";
170       break;
171     }
172     LOG(VERBOSE) << "device on " << address << " uptime " << uptime;
173     sleep(kAdbCommandGapTime);
174   }
175   LOG(DEBUG) << "Sending adb disconnect";
176   AdbDisconnect(address);
177   sleep(kAdbCommandGapTime);
178 }
179 
180 }  // namespace
181 
EstablishAndMaintainConnection(const std::string & address)182 [[noreturn]] void EstablishAndMaintainConnection(const std::string& address) {
183   while (true) {
184     EstablishConnection(address);
185     WaitForAdbDisconnection(address);
186   }
187 }
188 
189 }  // namespace cuttlefish
190