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         ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
286         output_queue_.pop_front();
287         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
288             PLOG(ERROR) << "adbd_auth: failed to write to framework fd";
289             ReplaceFrameworkFd(unique_fd());
290             return false;
291         }
292 
293         return true;
294     }
295 
RunAdbdAuthContext296     void Run() {
297         if (sock_fd_ == -1) {
298             LOG(ERROR) << "adbd_auth: socket unavailable, disabling user prompts";
299         } else {
300             struct epoll_event event;
301             event.events = EPOLLIN;
302             event.data.u64 = kEpollConstSocket;
303             CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, sock_fd_.get(), &event));
304         }
305 
306         {
307             struct epoll_event event;
308             event.events = EPOLLIN;
309             event.data.u64 = kEpollConstEventFd;
310             CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event));
311         }
312 
313         while (true) {
314             struct epoll_event events[3];
315             int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1));
316             if (rc == -1) {
317                 PLOG(FATAL) << "adbd_auth: epoll_wait failed";
318             } else if (rc == 0) {
319                 LOG(FATAL) << "adbd_auth: epoll_wait returned 0";
320             }
321 
322             bool restart = false;
323             for (int i = 0; i < rc; ++i) {
324                 if (restart) {
325                     break;
326                 }
327 
328                 struct epoll_event& event = events[i];
329                 switch (event.data.u64) {
330                     case kEpollConstSocket: {
331                         unique_fd new_framework_fd(accept4(sock_fd_.get(), nullptr, nullptr,
332                                                            SOCK_CLOEXEC | SOCK_NONBLOCK));
333                         if (new_framework_fd == -1) {
334                             PLOG(FATAL) << "adbd_auth: failed to accept framework fd";
335                         }
336 
337                         LOG(INFO) << "adbd_auth: received a new framework connection";
338                         std::lock_guard<std::mutex> lock(mutex_);
339                         ReplaceFrameworkFd(std::move(new_framework_fd));
340 
341                         // Stop iterating over events: one of the later ones might be the old
342                         // framework fd.
343                         restart = false;
344                         break;
345                     }
346 
347                     case kEpollConstEventFd: {
348                         // We were woken up to write something.
349                         uint64_t dummy;
350                         int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy)));
351                         if (rc != 8) {
352                             PLOG(FATAL)
353                                     << "adbd_auth: failed to read from eventfd (rc = " << rc << ")";
354                         }
355 
356                         std::lock_guard<std::mutex> lock(mutex_);
357                         UpdateFrameworkWritable();
358                         break;
359                     }
360 
361                     case kEpollConstFramework: {
362                         char buf[4096];
363                         if (event.events & EPOLLIN) {
364                             int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf)));
365                             if (rc == -1) {
366                                 LOG(FATAL) << "adbd_auth: failed to read from framework fd";
367                             } else if (rc == 0) {
368                                 LOG(INFO) << "adbd_auth: hit EOF on framework fd";
369                                 std::lock_guard<std::mutex> lock(mutex_);
370                                 ReplaceFrameworkFd(unique_fd());
371                             } else {
372                                 HandlePacket(std::string_view(buf, rc));
373                             }
374                         }
375 
376                         if (event.events & EPOLLOUT) {
377                             std::lock_guard<std::mutex> lock(mutex_);
378                             while (SendPacket()) {
379                                 continue;
380                             }
381                             UpdateFrameworkWritable();
382                         }
383 
384                         break;
385                     }
386                 }
387             }
388         }
389     }
390 
391     static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"};
IteratePublicKeysAdbdAuthContext392     void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
393         for (const auto& path : key_paths) {
394             if (access(path, R_OK) == 0) {
395                 LOG(INFO) << "adbd_auth: loading keys from " << path;
396                 std::string content;
397                 if (!android::base::ReadFileToString(path, &content)) {
398                     PLOG(ERROR) << "adbd_auth: couldn't read " << path;
399                     continue;
400                 }
401                 for (const auto& line : android::base::Split(content, "\n")) {
402                     if (!callback(opaque, line.data(), line.size())) {
403                         return;
404                     }
405                 }
406             }
407         }
408     }
409 
PromptUserAdbdAuthContext410     uint64_t PromptUser(std::string_view public_key, void* arg) EXCLUDES(mutex_) {
411         uint64_t id = NextId();
412 
413         std::lock_guard<std::mutex> lock(mutex_);
414         LOG(INFO) << "adbd_auth: sending prompt with id " << id;
415         pending_prompts_.emplace_back(id, public_key, arg);
416         DispatchPendingPrompt();
417         return id;
418     }
419 
NotifyAuthenticatedAdbdAuthContext420     uint64_t NotifyAuthenticated(std::string_view public_key) EXCLUDES(mutex_) {
421         uint64_t id = NextId();
422         std::lock_guard<std::mutex> lock(mutex_);
423         keys_.emplace(id, public_key);
424         output_queue_.emplace_back(
425                 AdbdAuthPacketAuthenticated{.public_key = std::string(public_key)});
426         return id;
427     }
428 
NotifyDisconnectedAdbdAuthContext429     void NotifyDisconnected(uint64_t id) EXCLUDES(mutex_) {
430         std::lock_guard<std::mutex> lock(mutex_);
431         auto it = keys_.find(id);
432         if (it == keys_.end()) {
433             LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection, skipping";
434             return;
435         }
436         output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)});
437         keys_.erase(it);
438     }
439 
NotifyTlsDeviceConnectedAdbdAuthContext440     uint64_t NotifyTlsDeviceConnected(AdbTransportType type,
441                                       std::string_view public_key) EXCLUDES(mutex_) {
442         uint64_t id = NextId();
443         std::lock_guard<std::mutex> lock(mutex_);
444         keys_.emplace(id, public_key);
445         output_queue_.emplace_back(AdbdPacketTlsDeviceConnected{
446                 .transport_type = static_cast<uint8_t>(type),
447                 .public_key = std::string(public_key)});
448         Interrupt();
449         return id;
450     }
451 
NotifyTlsDeviceDisconnectedAdbdAuthContext452     void NotifyTlsDeviceDisconnected(AdbTransportType type, uint64_t id) EXCLUDES(mutex_) {
453         std::lock_guard<std::mutex> lock(mutex_);
454         auto it = keys_.find(id);
455         if (it == keys_.end()) {
456             LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection of tls "
457                           "device, skipping";
458             return;
459         }
460         output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{
461                 .transport_type = static_cast<uint8_t>(type),
462                 .public_key = std::move(it->second)});
463         keys_.erase(it);
464         Interrupt();
465     }
466 
467     // Interrupt the worker thread to do some work.
InterruptAdbdAuthContext468     void Interrupt() {
469         uint64_t value = 1;
470         ssize_t rc = write(event_fd_.get(), &value, sizeof(value));
471         if (rc == -1) {
472             PLOG(FATAL) << "adbd_auth: write to eventfd failed";
473         } else if (rc != sizeof(value)) {
474             LOG(FATAL) << "adbd_auth: write to eventfd returned short (" << rc << ")";
475         }
476     }
477 
InitFrameworkHandlersAdbdAuthContext478     void InitFrameworkHandlers() {
479         // Framework wants to disconnect from a secured wifi device
480         framework_handlers_.emplace_back(
481                 FrameworkPktHandler{
482                     .code = "DD",
483                     .cb = std::bind(&AdbdAuthContext::KeyRemoved, this, std::placeholders::_1)});
484         // Framework allows USB debugging for the device
485         framework_handlers_.emplace_back(
486                 FrameworkPktHandler{
487                     .code = "OK",
488                     .cb = std::bind(&AdbdAuthContext::AllowUsbDevice, this, std::placeholders::_1)});
489         // Framework denies USB debugging for the device
490         framework_handlers_.emplace_back(
491                 FrameworkPktHandler{
492                     .code = "NO",
493                     .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this, std::placeholders::_1)});
494     }
495 
496     unique_fd epoll_fd_;
497     unique_fd event_fd_;
498     unique_fd sock_fd_;
499     unique_fd framework_fd_;
500 
501     std::atomic<uint64_t> next_id_;
502     AdbdAuthCallbacksV1 callbacks_;
503 
504     std::mutex mutex_;
505     std::unordered_map<uint64_t, std::string> keys_ GUARDED_BY(mutex_);
506 
507     // We keep two separate queues: one to handle backpressure from the socket (output_queue_)
508     // and one to make sure we only dispatch one authrequest at a time (pending_prompts_).
509     std::deque<AdbdAuthPacket> output_queue_ GUARDED_BY(mutex_);
510 
511     std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_);
512     std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_);
513 
514     // This is a list of commands that the framework could send to us.
515     using FrameworkHandlerCb = std::function<void(std::string_view)>;
516     struct FrameworkPktHandler {
517         const char* code;
518         FrameworkHandlerCb cb;
519     };
520     std::vector<FrameworkPktHandler> framework_handlers_;
521 };
522 
adbd_auth_new(AdbdAuthCallbacks * callbacks)523 AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
524     if (callbacks->version == 1) {
525         return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
526     } else {
527         LOG(ERROR) << "adbd_auth: received unknown AdbdAuthCallbacks version "
528                    << callbacks->version;
529         return nullptr;
530     }
531 }
532 
adbd_auth_delete(AdbdAuthContext * ctx)533 void adbd_auth_delete(AdbdAuthContext* ctx) {
534     delete ctx;
535 }
536 
adbd_auth_run(AdbdAuthContext * ctx)537 void adbd_auth_run(AdbdAuthContext* ctx) {
538     return ctx->Run();
539 }
540 
adbd_auth_get_public_keys(AdbdAuthContext * ctx,bool (* callback)(void * opaque,const char * public_key,size_t len),void * opaque)541 void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
542                                bool (*callback)(void* opaque, const char* public_key, size_t len),
543                                void* opaque) {
544     ctx->IteratePublicKeys(callback, opaque);
545 }
546 
adbd_auth_notify_auth(AdbdAuthContext * ctx,const char * public_key,size_t len)547 uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) {
548     return ctx->NotifyAuthenticated(std::string_view(public_key, len));
549 }
550 
adbd_auth_notify_disconnect(AdbdAuthContext * ctx,uint64_t id)551 void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) {
552     return ctx->NotifyDisconnected(id);
553 }
554 
adbd_auth_prompt_user(AdbdAuthContext * ctx,const char * public_key,size_t len,void * opaque)555 void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
556                            void* opaque) {
557     adbd_auth_prompt_user_with_id(ctx, public_key, len, opaque);
558 }
559 
adbd_auth_prompt_user_with_id(AdbdAuthContext * ctx,const char * public_key,size_t len,void * opaque)560 uint64_t adbd_auth_prompt_user_with_id(AdbdAuthContext* ctx, const char* public_key, size_t len,
561                                        void* opaque) {
562     return ctx->PromptUser(std::string_view(public_key, len), opaque);
563 }
564 
adbd_auth_tls_device_connected(AdbdAuthContext * ctx,AdbTransportType type,const char * public_key,size_t len)565 uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
566                                         AdbTransportType type,
567                                         const char* public_key,
568                                         size_t len) {
569     return ctx->NotifyTlsDeviceConnected(type, std::string_view(public_key, len));
570 }
571 
adbd_auth_tls_device_disconnected(AdbdAuthContext * ctx,AdbTransportType type,uint64_t id)572 void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
573                                        AdbTransportType type,
574                                        uint64_t id) {
575     ctx->NotifyTlsDeviceDisconnected(type, id);
576 }
577 
adbd_auth_get_max_version()578 uint32_t adbd_auth_get_max_version() {
579     return kAuthVersion;
580 }
581 
adbd_auth_supports_feature(AdbdAuthFeature f)582 bool adbd_auth_supports_feature(AdbdAuthFeature f) {
583     UNUSED(f);
584     return false;
585 }
586