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