blob: 5a0d3f61684b6834ce392a0230658846c8cd2c88 [file] [log] [blame]
Josh Gaob789fb12019-10-24 19:02:14 -07001/*
2 * Copyright (C) 2019 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#define ANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION
18
19#include "include/adbd_auth.h"
20
21#include <inttypes.h>
22#include <sys/epoll.h>
23#include <sys/eventfd.h>
24#include <sys/uio.h>
25
26#include <chrono>
27#include <deque>
28#include <string>
29#include <string_view>
30#include <tuple>
31#include <unordered_map>
32#include <utility>
33#include <variant>
34#include <vector>
35
36#include <android-base/file.h>
37#include <android-base/logging.h>
38#include <android-base/macros.h>
39#include <android-base/strings.h>
40#include <android-base/thread_annotations.h>
41#include <android-base/unique_fd.h>
42#include <cutils/sockets.h>
43
44using android::base::unique_fd;
45
Joshua Duong3d0860e2019-10-11 15:43:47 -070046static constexpr uint32_t kAuthVersion = 1;
47
Josh Gaob789fb12019-10-24 19:02:14 -070048struct AdbdAuthPacketAuthenticated {
49 std::string public_key;
50};
51
52struct AdbdAuthPacketDisconnected {
53 std::string public_key;
54};
55
56struct AdbdAuthPacketRequestAuthorization {
57 std::string public_key;
58};
59
Joshua Duong3d0860e2019-10-11 15:43:47 -070060struct AdbdPacketTlsDeviceConnected {
61 uint8_t transport_type;
62 std::string public_key;
63};
64
65struct AdbdPacketTlsDeviceDisconnected {
66 uint8_t transport_type;
67 std::string public_key;
68};
69
70using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated,
71 AdbdAuthPacketDisconnected,
72 AdbdAuthPacketRequestAuthorization,
73 AdbdPacketTlsDeviceConnected,
74 AdbdPacketTlsDeviceDisconnected>;
Josh Gaob789fb12019-10-24 19:02:14 -070075
76struct AdbdAuthContext {
77 static constexpr uint64_t kEpollConstSocket = 0;
78 static constexpr uint64_t kEpollConstEventFd = 1;
79 static constexpr uint64_t kEpollConstFramework = 2;
80
81public:
82 explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) {
Joshua Duong3d0860e2019-10-11 15:43:47 -070083 InitFrameworkHandlers();
Josh Gaob789fb12019-10-24 19:02:14 -070084 epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
85 if (epoll_fd_ == -1) {
86 PLOG(FATAL) << "failed to create epoll fd";
87 }
88
89 event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
90 if (event_fd_ == -1) {
91 PLOG(FATAL) << "failed to create eventfd";
92 }
93
94 sock_fd_.reset(android_get_control_socket("adbd"));
95 if (sock_fd_ == -1) {
96 PLOG(ERROR) << "failed to get adbd authentication socket";
97 } else {
98 if (fcntl(sock_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) {
99 PLOG(FATAL) << "failed to make adbd authentication socket cloexec";
100 }
101
102 if (fcntl(sock_fd_.get(), F_SETFL, O_NONBLOCK) != 0) {
103 PLOG(FATAL) << "failed to make adbd authentication socket nonblocking";
104 }
105
106 if (listen(sock_fd_.get(), 4) != 0) {
107 PLOG(FATAL) << "failed to listen on adbd authentication socket";
108 }
109 }
110 }
111
112 AdbdAuthContext(const AdbdAuthContext& copy) = delete;
113 AdbdAuthContext(AdbdAuthContext&& move) = delete;
114 AdbdAuthContext& operator=(const AdbdAuthContext& copy) = delete;
115 AdbdAuthContext& operator=(AdbdAuthContext&& move) = delete;
116
117 uint64_t NextId() { return next_id_++; }
118
119 void DispatchPendingPrompt() REQUIRES(mutex_) {
120 if (dispatched_prompt_) {
121 LOG(INFO) << "adbd_auth: prompt currently pending, skipping";
122 return;
123 }
124
125 if (pending_prompts_.empty()) {
126 LOG(INFO) << "adbd_auth: no prompts to send";
127 return;
128 }
129
130 LOG(INFO) << "adbd_auth: prompting user for adb authentication";
131 auto [id, public_key, arg] = std::move(pending_prompts_.front());
132 pending_prompts_.pop_front();
133
134 this->output_queue_.emplace_back(
135 AdbdAuthPacketRequestAuthorization{.public_key = public_key});
136
137 Interrupt();
138 dispatched_prompt_ = std::make_tuple(id, public_key, arg);
139 }
140
141 void UpdateFrameworkWritable() REQUIRES(mutex_) {
142 // This might result in redundant calls to EPOLL_CTL_MOD if, for example, we get notified
143 // at the same time as a framework connection, but that's unlikely and this doesn't need to
144 // be fast anyway.
145 if (framework_fd_ != -1) {
146 struct epoll_event event;
147 event.events = EPOLLIN;
148 if (!output_queue_.empty()) {
149 LOG(INFO) << "marking framework writable";
150 event.events |= EPOLLOUT;
151 }
152 event.data.u64 = kEpollConstFramework;
153 CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_MOD, framework_fd_.get(), &event));
154 }
155 }
156
157 void ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) {
158 LOG(INFO) << "received new framework fd " << new_fd.get()
159 << " (current = " << framework_fd_.get() << ")";
160
161 // If we already had a framework fd, clean up after ourselves.
162 if (framework_fd_ != -1) {
163 output_queue_.clear();
164 dispatched_prompt_.reset();
165 CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, framework_fd_.get(), nullptr));
166 framework_fd_.reset();
167 }
168
169 if (new_fd != -1) {
170 struct epoll_event event;
171 event.events = EPOLLIN;
172 if (!output_queue_.empty()) {
173 LOG(INFO) << "marking framework writable";
174 event.events |= EPOLLOUT;
175 }
176 event.data.u64 = kEpollConstFramework;
177 CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, new_fd.get(), &event));
178 framework_fd_ = std::move(new_fd);
179 }
180 }
181
Joshua Duong3d0860e2019-10-11 15:43:47 -0700182 void HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
Josh Gaob789fb12019-10-24 19:02:14 -0700183 LOG(INFO) << "received packet: " << packet;
184
Joshua Duong3d0860e2019-10-11 15:43:47 -0700185 if (packet.size() < 2) {
186 LOG(ERROR) << "received packet of invalid length";
187 std::lock_guard<std::mutex> lock(mutex_);
188 ReplaceFrameworkFd(unique_fd());
Josh Gaob789fb12019-10-24 19:02:14 -0700189 }
190
Joshua Duong3d0860e2019-10-11 15:43:47 -0700191 bool handled_packet = false;
192 for (size_t i = 0; i < framework_handlers_.size(); ++i) {
193 if (android::base::ConsumePrefix(&packet, framework_handlers_[i].code)) {
194 framework_handlers_[i].cb(packet);
195 handled_packet = true;
196 break;
197 }
Josh Gaob789fb12019-10-24 19:02:14 -0700198 }
Joshua Duong3d0860e2019-10-11 15:43:47 -0700199 if (!handled_packet) {
200 LOG(ERROR) << "unhandled packet: " << packet;
201 std::lock_guard<std::mutex> lock(mutex_);
202 ReplaceFrameworkFd(unique_fd());
203 }
204 }
205
206 void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
207 std::lock_guard<std::mutex> lock(mutex_);
208 CHECK(buf.empty());
209 CHECK(dispatched_prompt_.has_value());
210 auto& [id, key, arg] = *dispatched_prompt_;
211 keys_.emplace(id, std::move(key));
212
213 callbacks_.key_authorized(arg, id);
214 dispatched_prompt_ = std::nullopt;
215
216 // We need to dispatch pending prompts here upon success as well,
217 // since we might have multiple queued prompts.
218 DispatchPendingPrompt();
219 }
220
221 void DenyUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
222 std::lock_guard<std::mutex> lock(mutex_);
223 CHECK(buf.empty());
224 // TODO: Do we want a callback if the key is denied?
225 dispatched_prompt_ = std::nullopt;
226 DispatchPendingPrompt();
227 }
228
229 void KeyRemoved(std::string_view buf) EXCLUDES(mutex_) {
230 CHECK(!buf.empty());
231 callbacks_.key_removed(buf.data(), buf.size());
Josh Gaob789fb12019-10-24 19:02:14 -0700232 }
233
234 bool SendPacket() REQUIRES(mutex_) {
235 if (output_queue_.empty()) {
236 return false;
237 }
238
239 CHECK_NE(-1, framework_fd_.get());
240
241 auto& packet = output_queue_.front();
Joshua Duong3d0860e2019-10-11 15:43:47 -0700242 struct iovec iovs[3];
243 int iovcnt = 2;
Josh Gaob789fb12019-10-24 19:02:14 -0700244 if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) {
245 iovs[0].iov_base = const_cast<char*>("CK");
246 iovs[0].iov_len = 2;
247 iovs[1].iov_base = p->public_key.data();
248 iovs[1].iov_len = p->public_key.size();
249 } else if (auto* p = std::get_if<AdbdAuthPacketDisconnected>(&packet)) {
250 iovs[0].iov_base = const_cast<char*>("DC");
251 iovs[0].iov_len = 2;
252 iovs[1].iov_base = p->public_key.data();
253 iovs[1].iov_len = p->public_key.size();
254 } else if (auto* p = std::get_if<AdbdAuthPacketRequestAuthorization>(&packet)) {
255 iovs[0].iov_base = const_cast<char*>("PK");
256 iovs[0].iov_len = 2;
257 iovs[1].iov_base = p->public_key.data();
258 iovs[1].iov_len = p->public_key.size();
Joshua Duong3d0860e2019-10-11 15:43:47 -0700259 } else if (auto* p = std::get_if<AdbdPacketTlsDeviceConnected>(&packet)) {
260 iovcnt = 3;
261 iovs[0].iov_base = const_cast<char*>("WE");
262 iovs[0].iov_len = 2;
263 iovs[1].iov_base = &p->transport_type;
264 iovs[1].iov_len = 1;
265 iovs[2].iov_base = p->public_key.data();
266 iovs[2].iov_len = p->public_key.size();
267 } else if (auto* p = std::get_if<AdbdPacketTlsDeviceDisconnected>(&packet)) {
268 iovcnt = 3;
269 iovs[0].iov_base = const_cast<char*>("WF");
270 iovs[0].iov_len = 2;
271 iovs[1].iov_base = &p->transport_type;
272 iovs[1].iov_len = 1;
273 iovs[2].iov_base = p->public_key.data();
274 iovs[2].iov_len = p->public_key.size();
Josh Gaob789fb12019-10-24 19:02:14 -0700275 } else {
276 LOG(FATAL) << "unhandled packet type?";
277 }
278
279 output_queue_.pop_front();
280
Joshua Duong3d0860e2019-10-11 15:43:47 -0700281 ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
Josh Gaob789fb12019-10-24 19:02:14 -0700282 if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
283 PLOG(ERROR) << "failed to write to framework fd";
284 ReplaceFrameworkFd(unique_fd());
285 return false;
286 }
287
288 return true;
289 }
290
291 void Run() {
292 if (sock_fd_ == -1) {
293 LOG(ERROR) << "adbd authentication socket unavailable, disabling user prompts";
294 } else {
295 struct epoll_event event;
296 event.events = EPOLLIN;
297 event.data.u64 = kEpollConstSocket;
298 CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, sock_fd_.get(), &event));
299 }
300
301 {
302 struct epoll_event event;
303 event.events = EPOLLIN;
304 event.data.u64 = kEpollConstEventFd;
305 CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event));
306 }
307
308 while (true) {
309 struct epoll_event events[3];
310 int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1));
311 if (rc == -1) {
312 PLOG(FATAL) << "epoll_wait failed";
313 } else if (rc == 0) {
314 LOG(FATAL) << "epoll_wait returned 0";
315 }
316
317 bool restart = false;
318 for (int i = 0; i < rc; ++i) {
319 if (restart) {
320 break;
321 }
322
323 struct epoll_event& event = events[i];
324 switch (event.data.u64) {
325 case kEpollConstSocket: {
326 unique_fd new_framework_fd(accept4(sock_fd_.get(), nullptr, nullptr,
327 SOCK_CLOEXEC | SOCK_NONBLOCK));
328 if (new_framework_fd == -1) {
329 PLOG(FATAL) << "failed to accept framework fd";
330 }
331
332 LOG(INFO) << "adbd_auth: received a new framework connection";
333 std::lock_guard<std::mutex> lock(mutex_);
334 ReplaceFrameworkFd(std::move(new_framework_fd));
335
336 // Stop iterating over events: one of the later ones might be the old
337 // framework fd.
338 restart = false;
339 break;
340 }
341
342 case kEpollConstEventFd: {
343 // We were woken up to write something.
344 uint64_t dummy;
345 int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy)));
346 if (rc != 8) {
347 PLOG(FATAL) << "failed to read from eventfd (rc = " << rc << ")";
348 }
349
350 std::lock_guard<std::mutex> lock(mutex_);
351 UpdateFrameworkWritable();
352 break;
353 }
354
355 case kEpollConstFramework: {
356 char buf[4096];
357 if (event.events & EPOLLIN) {
358 int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf)));
359 if (rc == -1) {
360 LOG(FATAL) << "failed to read from framework fd";
361 } else if (rc == 0) {
362 LOG(INFO) << "hit EOF on framework fd";
363 std::lock_guard<std::mutex> lock(mutex_);
364 ReplaceFrameworkFd(unique_fd());
365 } else {
Josh Gaob789fb12019-10-24 19:02:14 -0700366 HandlePacket(std::string_view(buf, rc));
367 }
368 }
369
370 if (event.events & EPOLLOUT) {
371 std::lock_guard<std::mutex> lock(mutex_);
372 while (SendPacket()) {
373 continue;
374 }
375 UpdateFrameworkWritable();
376 }
377
378 break;
379 }
380 }
381 }
382 }
383 }
384
385 static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"};
Joshua Duong3d0860e2019-10-11 15:43:47 -0700386 void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
Josh Gaob789fb12019-10-24 19:02:14 -0700387 for (const auto& path : key_paths) {
388 if (access(path, R_OK) == 0) {
389 LOG(INFO) << "Loading keys from " << path;
390 std::string content;
391 if (!android::base::ReadFileToString(path, &content)) {
392 PLOG(ERROR) << "Couldn't read " << path;
393 continue;
394 }
395 for (const auto& line : android::base::Split(content, "\n")) {
Joshua Duong3d0860e2019-10-11 15:43:47 -0700396 if (!callback(opaque, line.data(), line.size())) {
Josh Gaob789fb12019-10-24 19:02:14 -0700397 return;
398 }
399 }
400 }
401 }
402 }
403
404 uint64_t PromptUser(std::string_view public_key, void* arg) EXCLUDES(mutex_) {
405 uint64_t id = NextId();
406
407 std::lock_guard<std::mutex> lock(mutex_);
408 pending_prompts_.emplace_back(id, public_key, arg);
409 DispatchPendingPrompt();
410 return id;
411 }
412
413 uint64_t NotifyAuthenticated(std::string_view public_key) EXCLUDES(mutex_) {
414 uint64_t id = NextId();
415 std::lock_guard<std::mutex> lock(mutex_);
416 keys_.emplace(id, public_key);
417 output_queue_.emplace_back(
Joshua Duong3d0860e2019-10-11 15:43:47 -0700418 AdbdAuthPacketAuthenticated{.public_key = std::string(public_key)});
Josh Gaob789fb12019-10-24 19:02:14 -0700419 return id;
420 }
421
422 void NotifyDisconnected(uint64_t id) EXCLUDES(mutex_) {
423 std::lock_guard<std::mutex> lock(mutex_);
424 auto it = keys_.find(id);
425 if (it == keys_.end()) {
426 LOG(DEBUG) << "couldn't find public key to notify disconnection, skipping";
427 return;
428 }
429 output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)});
430 keys_.erase(it);
431 }
432
Joshua Duong3d0860e2019-10-11 15:43:47 -0700433 uint64_t NotifyTlsDeviceConnected(AdbTransportType type,
434 std::string_view public_key) EXCLUDES(mutex_) {
435 uint64_t id = NextId();
436 std::lock_guard<std::mutex> lock(mutex_);
437 keys_.emplace(id, public_key);
438 output_queue_.emplace_back(AdbdPacketTlsDeviceConnected{
439 .transport_type = static_cast<uint8_t>(type),
440 .public_key = std::string(public_key)});
441 Interrupt();
442 return id;
443 }
444
445 void NotifyTlsDeviceDisconnected(AdbTransportType type, uint64_t id) EXCLUDES(mutex_) {
446 std::lock_guard<std::mutex> lock(mutex_);
447 auto it = keys_.find(id);
448 if (it == keys_.end()) {
449 LOG(DEBUG) << "couldn't find public key to notify disconnection of tls device, skipping";
450 return;
451 }
452 output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{
453 .transport_type = static_cast<uint8_t>(type),
454 .public_key = std::move(it->second)});
455 keys_.erase(it);
456 Interrupt();
457 }
458
Josh Gaob789fb12019-10-24 19:02:14 -0700459 // Interrupt the worker thread to do some work.
460 void Interrupt() {
461 uint64_t value = 1;
462 ssize_t rc = write(event_fd_.get(), &value, sizeof(value));
463 if (rc == -1) {
464 PLOG(FATAL) << "write to eventfd failed";
465 } else if (rc != sizeof(value)) {
466 LOG(FATAL) << "write to eventfd returned short (" << rc << ")";
467 }
468 }
469
Joshua Duong3d0860e2019-10-11 15:43:47 -0700470 void InitFrameworkHandlers() {
471 // Framework wants to disconnect from a secured wifi device
472 framework_handlers_.emplace_back(
473 FrameworkPktHandler{
474 .code = "DD",
475 .cb = std::bind(&AdbdAuthContext::KeyRemoved, this, std::placeholders::_1)});
476 // Framework allows USB debugging for the device
477 framework_handlers_.emplace_back(
478 FrameworkPktHandler{
479 .code = "OK",
480 .cb = std::bind(&AdbdAuthContext::AllowUsbDevice, this, std::placeholders::_1)});
481 // Framework denies USB debugging for the device
482 framework_handlers_.emplace_back(
483 FrameworkPktHandler{
484 .code = "NO",
485 .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this, std::placeholders::_1)});
486 }
487
Josh Gaob789fb12019-10-24 19:02:14 -0700488 unique_fd epoll_fd_;
489 unique_fd event_fd_;
490 unique_fd sock_fd_;
491 unique_fd framework_fd_;
492
493 std::atomic<uint64_t> next_id_;
494 AdbdAuthCallbacksV1 callbacks_;
495
496 std::mutex mutex_;
497 std::unordered_map<uint64_t, std::string> keys_ GUARDED_BY(mutex_);
498
499 // We keep two separate queues: one to handle backpressure from the socket (output_queue_)
500 // and one to make sure we only dispatch one authrequest at a time (pending_prompts_).
Joshua Duong3d0860e2019-10-11 15:43:47 -0700501 std::deque<AdbdAuthPacket> output_queue_ GUARDED_BY(mutex_);
Josh Gaob789fb12019-10-24 19:02:14 -0700502
503 std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_);
504 std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_);
Joshua Duong3d0860e2019-10-11 15:43:47 -0700505
506 // This is a list of commands that the framework could send to us.
507 using FrameworkHandlerCb = std::function<void(std::string_view)>;
508 struct FrameworkPktHandler {
509 const char* code;
510 FrameworkHandlerCb cb;
511 };
512 std::vector<FrameworkPktHandler> framework_handlers_;
Josh Gaob789fb12019-10-24 19:02:14 -0700513};
514
515AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
Joshua Duong3d0860e2019-10-11 15:43:47 -0700516 if (callbacks->version == 1) {
517 return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
518 } else {
Josh Gaob789fb12019-10-24 19:02:14 -0700519 LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version;
520 return nullptr;
521 }
Josh Gaob789fb12019-10-24 19:02:14 -0700522}
523
524void adbd_auth_delete(AdbdAuthContext* ctx) {
525 delete ctx;
526}
527
528void adbd_auth_run(AdbdAuthContext* ctx) {
529 return ctx->Run();
530}
531
532void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
Joshua Duong3d0860e2019-10-11 15:43:47 -0700533 bool (*callback)(void* opaque, const char* public_key, size_t len),
534 void* opaque) {
535 ctx->IteratePublicKeys(callback, opaque);
Josh Gaob789fb12019-10-24 19:02:14 -0700536}
537
538uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) {
539 return ctx->NotifyAuthenticated(std::string_view(public_key, len));
540}
541
542void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) {
543 return ctx->NotifyDisconnected(id);
544}
545
546void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
Joshua Duong3d0860e2019-10-11 15:43:47 -0700547 void* opaque) {
548 ctx->PromptUser(std::string_view(public_key, len), opaque);
Josh Gaob789fb12019-10-24 19:02:14 -0700549}
550
Joshua Duong3d0860e2019-10-11 15:43:47 -0700551uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
552 AdbTransportType type,
553 const char* public_key,
554 size_t len) {
555 return ctx->NotifyTlsDeviceConnected(type, std::string_view(public_key, len));
556}
557
558void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
559 AdbTransportType type,
560 uint64_t id) {
561 ctx->NotifyTlsDeviceDisconnected(type, id);
562}
563
564uint32_t adbd_auth_get_max_version() {
565 return kAuthVersion;
566}
567
568bool adbd_auth_supports_feature(AdbdAuthFeature f) {
569 UNUSED(f);
Josh Gaob789fb12019-10-24 19:02:14 -0700570 return false;
571}