1 /*
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
44 using android::base::unique_fd;
45
46 static constexpr uint32_t kAuthVersion = 1;
47
48 struct AdbdAuthPacketAuthenticated {
49 std::string public_key;
50 };
51
52 struct AdbdAuthPacketDisconnected {
53 std::string public_key;
54 };
55
56 struct AdbdAuthPacketRequestAuthorization {
57 std::string public_key;
58 };
59
60 struct AdbdPacketTlsDeviceConnected {
61 uint8_t transport_type;
62 std::string public_key;
63 };
64
65 struct AdbdPacketTlsDeviceDisconnected {
66 uint8_t transport_type;
67 std::string public_key;
68 };
69
70 using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated,
71 AdbdAuthPacketDisconnected,
72 AdbdAuthPacketRequestAuthorization,
73 AdbdPacketTlsDeviceConnected,
74 AdbdPacketTlsDeviceDisconnected>;
75
76 struct AdbdAuthContext {
77 static constexpr uint64_t kEpollConstSocket = 0;
78 static constexpr uint64_t kEpollConstEventFd = 1;
79 static constexpr uint64_t kEpollConstFramework = 2;
80
81 public:
AdbdAuthContextAdbdAuthContext82 explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) {
83 InitFrameworkHandlers();
84 epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
85 if (epoll_fd_ == -1) {
86 PLOG(FATAL) << "adbd_auth: 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) << "adbd_auth: failed to create eventfd";
92 }
93
94 sock_fd_.reset(android_get_control_socket("adbd"));
95 if (sock_fd_ == -1) {
96 PLOG(ERROR) << "adbd_auth: failed to get adbd authentication socket";
97 } else {
98 if (fcntl(sock_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) {
99 PLOG(FATAL) << "adbd_auth: failed to make adbd authentication socket cloexec";
100 }
101
102 if (fcntl(sock_fd_.get(), F_SETFL, O_NONBLOCK) != 0) {
103 PLOG(FATAL) << "adbd_auth: failed to make adbd authentication socket nonblocking";
104 }
105
106 if (listen(sock_fd_.get(), 4) != 0) {
107 PLOG(FATAL) << "adbd_auth: 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
NextIdAdbdAuthContext117 uint64_t NextId() { return next_id_++; }
118
DispatchPendingPromptAdbdAuthContext119 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
UpdateFrameworkWritableAdbdAuthContext141 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) << "adbd_auth: 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
ReplaceFrameworkFdAdbdAuthContext157 void ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) {
158 LOG(INFO) << "adbd_auth: 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) << "adbd_auth: 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
HandlePacketAdbdAuthContext182 void HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
183 LOG(INFO) << "adbd_auth: received packet: " << packet;
184
185 if (packet.size() < 2) {
186 LOG(ERROR) << "adbd_auth: received packet of invalid length";
187 std::lock_guard<std::mutex> lock(mutex_);
188 ReplaceFrameworkFd(unique_fd());
189 }
190
191 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 }
198 }
199 if (!handled_packet) {
200 LOG(ERROR) << "adbd_auth: unhandled packet: " << packet;
201 std::lock_guard<std::mutex> lock(mutex_);
202 ReplaceFrameworkFd(unique_fd());
203 }
204 }
205
AllowUsbDeviceAdbdAuthContext206 void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
207 std::lock_guard<std::mutex> lock(mutex_);
208 CHECK(buf.empty());
209
210 if (dispatched_prompt_.has_value()) {
211 // It's possible for the framework to send us a response without our having sent a
212 // request to it: e.g. if adbd restarts while we have a pending request.
213 auto& [id, key, arg] = *dispatched_prompt_;
214 keys_.emplace(id, std::move(key));
215
216 callbacks_.key_authorized(arg, id);
217 dispatched_prompt_ = std::nullopt;
218 } else {
219 LOG(WARNING) << "adbd_auth: received authorization for unknown prompt, ignoring";
220 }
221
222 // We need to dispatch pending prompts here upon success as well,
223 // since we might have multiple queued prompts.
224 DispatchPendingPrompt();
225 }
226
DenyUsbDeviceAdbdAuthContext227 void DenyUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
228 std::lock_guard<std::mutex> lock(mutex_);
229 CHECK(buf.empty());
230 // TODO: Do we want a callback if the key is denied?
231 dispatched_prompt_ = std::nullopt;
232 DispatchPendingPrompt();
233 }
234
KeyRemovedAdbdAuthContext235 void KeyRemoved(std::string_view buf) EXCLUDES(mutex_) {
236 CHECK(!buf.empty());
237 callbacks_.key_removed(buf.data(), buf.size());
238 }
239
SendPacketAdbdAuthContext240 bool SendPacket() REQUIRES(mutex_) {
241 if (output_queue_.empty()) {
242 return false;
243 }
244
245 CHECK_NE(-1, framework_fd_.get());
246
247 auto& packet = output_queue_.front();
248 struct iovec iovs[3];
249 int iovcnt = 2;
250 if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) {
251 iovs[0].iov_base = const_cast<char*>("CK");
252 iovs[0].iov_len = 2;
253 iovs[1].iov_base = p->public_key.data();
254 iovs[1].iov_len = p->public_key.size();
255 } else if (auto* p = std::get_if<AdbdAuthPacketDisconnected>(&packet)) {
256 iovs[0].iov_base = const_cast<char*>("DC");
257 iovs[0].iov_len = 2;
258 iovs[1].iov_base = p->public_key.data();
259 iovs[1].iov_len = p->public_key.size();
260 } else if (auto* p = std::get_if<AdbdAuthPacketRequestAuthorization>(&packet)) {
261 iovs[0].iov_base = const_cast<char*>("PK");
262 iovs[0].iov_len = 2;
263 iovs[1].iov_base = p->public_key.data();
264 iovs[1].iov_len = p->public_key.size();
265 } else if (auto* p = std::get_if<AdbdPacketTlsDeviceConnected>(&packet)) {
266 iovcnt = 3;
267 iovs[0].iov_base = const_cast<char*>("WE");
268 iovs[0].iov_len = 2;
269 iovs[1].iov_base = &p->transport_type;
270 iovs[1].iov_len = 1;
271 iovs[2].iov_base = p->public_key.data();
272 iovs[2].iov_len = p->public_key.size();
273 } else if (auto* p = std::get_if<AdbdPacketTlsDeviceDisconnected>(&packet)) {
274 iovcnt = 3;
275 iovs[0].iov_base = const_cast<char*>("WF");
276 iovs[0].iov_len = 2;
277 iovs[1].iov_base = &p->transport_type;
278 iovs[1].iov_len = 1;
279 iovs[2].iov_base = p->public_key.data();
280 iovs[2].iov_len = p->public_key.size();
281 } else {
282 LOG(FATAL) << "adbd_auth: unhandled packet type?";
283 }
284
285 output_queue_.pop_front();
286
287 ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
288 if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
289 PLOG(ERROR) << "adbd_auth: failed to write to framework fd";
290 ReplaceFrameworkFd(unique_fd());
291 return false;
292 }
293
294 return true;
295 }
296
RunAdbdAuthContext297 void Run() {
298 if (sock_fd_ == -1) {
299 LOG(ERROR) << "adbd_auth: socket unavailable, disabling user prompts";
300 } else {
301 struct epoll_event event;
302 event.events = EPOLLIN;
303 event.data.u64 = kEpollConstSocket;
304 CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, sock_fd_.get(), &event));
305 }
306
307 {
308 struct epoll_event event;
309 event.events = EPOLLIN;
310 event.data.u64 = kEpollConstEventFd;
311 CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event));
312 }
313
314 while (true) {
315 struct epoll_event events[3];
316 int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1));
317 if (rc == -1) {
318 PLOG(FATAL) << "adbd_auth: epoll_wait failed";
319 } else if (rc == 0) {
320 LOG(FATAL) << "adbd_auth: epoll_wait returned 0";
321 }
322
323 bool restart = false;
324 for (int i = 0; i < rc; ++i) {
325 if (restart) {
326 break;
327 }
328
329 struct epoll_event& event = events[i];
330 switch (event.data.u64) {
331 case kEpollConstSocket: {
332 unique_fd new_framework_fd(accept4(sock_fd_.get(), nullptr, nullptr,
333 SOCK_CLOEXEC | SOCK_NONBLOCK));
334 if (new_framework_fd == -1) {
335 PLOG(FATAL) << "adbd_auth: failed to accept framework fd";
336 }
337
338 LOG(INFO) << "adbd_auth: received a new framework connection";
339 std::lock_guard<std::mutex> lock(mutex_);
340 ReplaceFrameworkFd(std::move(new_framework_fd));
341
342 // Stop iterating over events: one of the later ones might be the old
343 // framework fd.
344 restart = false;
345 break;
346 }
347
348 case kEpollConstEventFd: {
349 // We were woken up to write something.
350 uint64_t dummy;
351 int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy)));
352 if (rc != 8) {
353 PLOG(FATAL)
354 << "adbd_auth: failed to read from eventfd (rc = " << rc << ")";
355 }
356
357 std::lock_guard<std::mutex> lock(mutex_);
358 UpdateFrameworkWritable();
359 break;
360 }
361
362 case kEpollConstFramework: {
363 char buf[4096];
364 if (event.events & EPOLLIN) {
365 int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf)));
366 if (rc == -1) {
367 LOG(FATAL) << "adbd_auth: failed to read from framework fd";
368 } else if (rc == 0) {
369 LOG(INFO) << "adbd_auth: hit EOF on framework fd";
370 std::lock_guard<std::mutex> lock(mutex_);
371 ReplaceFrameworkFd(unique_fd());
372 } else {
373 HandlePacket(std::string_view(buf, rc));
374 }
375 }
376
377 if (event.events & EPOLLOUT) {
378 std::lock_guard<std::mutex> lock(mutex_);
379 while (SendPacket()) {
380 continue;
381 }
382 UpdateFrameworkWritable();
383 }
384
385 break;
386 }
387 }
388 }
389 }
390 }
391
392 static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"};
IteratePublicKeysAdbdAuthContext393 void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
394 for (const auto& path : key_paths) {
395 if (access(path, R_OK) == 0) {
396 LOG(INFO) << "adbd_auth: loading keys from " << path;
397 std::string content;
398 if (!android::base::ReadFileToString(path, &content)) {
399 PLOG(ERROR) << "adbd_auth: couldn't read " << path;
400 continue;
401 }
402 for (const auto& line : android::base::Split(content, "\n")) {
403 if (!callback(opaque, line.data(), line.size())) {
404 return;
405 }
406 }
407 }
408 }
409 }
410
PromptUserAdbdAuthContext411 uint64_t PromptUser(std::string_view public_key, void* arg) EXCLUDES(mutex_) {
412 uint64_t id = NextId();
413
414 std::lock_guard<std::mutex> lock(mutex_);
415 LOG(INFO) << "adbd_auth: sending prompt with id " << id;
416 pending_prompts_.emplace_back(id, public_key, arg);
417 DispatchPendingPrompt();
418 return id;
419 }
420
NotifyAuthenticatedAdbdAuthContext421 uint64_t NotifyAuthenticated(std::string_view public_key) EXCLUDES(mutex_) {
422 uint64_t id = NextId();
423 std::lock_guard<std::mutex> lock(mutex_);
424 keys_.emplace(id, public_key);
425 output_queue_.emplace_back(
426 AdbdAuthPacketAuthenticated{.public_key = std::string(public_key)});
427 return id;
428 }
429
NotifyDisconnectedAdbdAuthContext430 void NotifyDisconnected(uint64_t id) EXCLUDES(mutex_) {
431 std::lock_guard<std::mutex> lock(mutex_);
432 auto it = keys_.find(id);
433 if (it == keys_.end()) {
434 LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection, skipping";
435 return;
436 }
437 output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)});
438 keys_.erase(it);
439 }
440
NotifyTlsDeviceConnectedAdbdAuthContext441 uint64_t NotifyTlsDeviceConnected(AdbTransportType type,
442 std::string_view public_key) EXCLUDES(mutex_) {
443 uint64_t id = NextId();
444 std::lock_guard<std::mutex> lock(mutex_);
445 keys_.emplace(id, public_key);
446 output_queue_.emplace_back(AdbdPacketTlsDeviceConnected{
447 .transport_type = static_cast<uint8_t>(type),
448 .public_key = std::string(public_key)});
449 Interrupt();
450 return id;
451 }
452
NotifyTlsDeviceDisconnectedAdbdAuthContext453 void NotifyTlsDeviceDisconnected(AdbTransportType type, uint64_t id) EXCLUDES(mutex_) {
454 std::lock_guard<std::mutex> lock(mutex_);
455 auto it = keys_.find(id);
456 if (it == keys_.end()) {
457 LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection of tls "
458 "device, skipping";
459 return;
460 }
461 output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{
462 .transport_type = static_cast<uint8_t>(type),
463 .public_key = std::move(it->second)});
464 keys_.erase(it);
465 Interrupt();
466 }
467
468 // Interrupt the worker thread to do some work.
InterruptAdbdAuthContext469 void Interrupt() {
470 uint64_t value = 1;
471 ssize_t rc = write(event_fd_.get(), &value, sizeof(value));
472 if (rc == -1) {
473 PLOG(FATAL) << "adbd_auth: write to eventfd failed";
474 } else if (rc != sizeof(value)) {
475 LOG(FATAL) << "adbd_auth: write to eventfd returned short (" << rc << ")";
476 }
477 }
478
InitFrameworkHandlersAdbdAuthContext479 void InitFrameworkHandlers() {
480 // Framework wants to disconnect from a secured wifi device
481 framework_handlers_.emplace_back(
482 FrameworkPktHandler{
483 .code = "DD",
484 .cb = std::bind(&AdbdAuthContext::KeyRemoved, this, std::placeholders::_1)});
485 // Framework allows USB debugging for the device
486 framework_handlers_.emplace_back(
487 FrameworkPktHandler{
488 .code = "OK",
489 .cb = std::bind(&AdbdAuthContext::AllowUsbDevice, this, std::placeholders::_1)});
490 // Framework denies USB debugging for the device
491 framework_handlers_.emplace_back(
492 FrameworkPktHandler{
493 .code = "NO",
494 .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this, std::placeholders::_1)});
495 }
496
497 unique_fd epoll_fd_;
498 unique_fd event_fd_;
499 unique_fd sock_fd_;
500 unique_fd framework_fd_;
501
502 std::atomic<uint64_t> next_id_;
503 AdbdAuthCallbacksV1 callbacks_;
504
505 std::mutex mutex_;
506 std::unordered_map<uint64_t, std::string> keys_ GUARDED_BY(mutex_);
507
508 // We keep two separate queues: one to handle backpressure from the socket (output_queue_)
509 // and one to make sure we only dispatch one authrequest at a time (pending_prompts_).
510 std::deque<AdbdAuthPacket> output_queue_ GUARDED_BY(mutex_);
511
512 std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_);
513 std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_);
514
515 // This is a list of commands that the framework could send to us.
516 using FrameworkHandlerCb = std::function<void(std::string_view)>;
517 struct FrameworkPktHandler {
518 const char* code;
519 FrameworkHandlerCb cb;
520 };
521 std::vector<FrameworkPktHandler> framework_handlers_;
522 };
523
adbd_auth_new(AdbdAuthCallbacks * callbacks)524 AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
525 if (callbacks->version == 1) {
526 return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
527 } else {
528 LOG(ERROR) << "adbd_auth: received unknown AdbdAuthCallbacks version "
529 << callbacks->version;
530 return nullptr;
531 }
532 }
533
adbd_auth_delete(AdbdAuthContext * ctx)534 void adbd_auth_delete(AdbdAuthContext* ctx) {
535 delete ctx;
536 }
537
adbd_auth_run(AdbdAuthContext * ctx)538 void adbd_auth_run(AdbdAuthContext* ctx) {
539 return ctx->Run();
540 }
541
adbd_auth_get_public_keys(AdbdAuthContext * ctx,bool (* callback)(void * opaque,const char * public_key,size_t len),void * opaque)542 void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
543 bool (*callback)(void* opaque, const char* public_key, size_t len),
544 void* opaque) {
545 ctx->IteratePublicKeys(callback, opaque);
546 }
547
adbd_auth_notify_auth(AdbdAuthContext * ctx,const char * public_key,size_t len)548 uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) {
549 return ctx->NotifyAuthenticated(std::string_view(public_key, len));
550 }
551
adbd_auth_notify_disconnect(AdbdAuthContext * ctx,uint64_t id)552 void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) {
553 return ctx->NotifyDisconnected(id);
554 }
555
adbd_auth_prompt_user(AdbdAuthContext * ctx,const char * public_key,size_t len,void * opaque)556 void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
557 void* opaque) {
558 adbd_auth_prompt_user_with_id(ctx, public_key, len, opaque);
559 }
560
adbd_auth_prompt_user_with_id(AdbdAuthContext * ctx,const char * public_key,size_t len,void * opaque)561 uint64_t adbd_auth_prompt_user_with_id(AdbdAuthContext* ctx, const char* public_key, size_t len,
562 void* opaque) {
563 return ctx->PromptUser(std::string_view(public_key, len), opaque);
564 }
565
adbd_auth_tls_device_connected(AdbdAuthContext * ctx,AdbTransportType type,const char * public_key,size_t len)566 uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
567 AdbTransportType type,
568 const char* public_key,
569 size_t len) {
570 return ctx->NotifyTlsDeviceConnected(type, std::string_view(public_key, len));
571 }
572
adbd_auth_tls_device_disconnected(AdbdAuthContext * ctx,AdbTransportType type,uint64_t id)573 void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
574 AdbTransportType type,
575 uint64_t id) {
576 ctx->NotifyTlsDeviceDisconnected(type, id);
577 }
578
adbd_auth_get_max_version()579 uint32_t adbd_auth_get_max_version() {
580 return kAuthVersion;
581 }
582
adbd_auth_supports_feature(AdbdAuthFeature f)583 bool adbd_auth_supports_feature(AdbdAuthFeature f) {
584 UNUSED(f);
585 return false;
586 }
587