1 /*
2  * Copyright 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 #include "l2cap/classic/facade.h"
18 
19 #include <bluetooth/log.h>
20 
21 #include <condition_variable>
22 #include <cstdint>
23 #include <unordered_map>
24 
25 #include "blueberry/facade/l2cap/classic/facade.grpc.pb.h"
26 #include "common/bidi_queue.h"
27 #include "common/bind.h"
28 #include "common/callback.h"
29 #include "grpc/grpc_event_queue.h"
30 #include "hci/address.h"
31 #include "l2cap/classic/l2cap_classic_module.h"
32 #include "os/log.h"
33 #include "packet/raw_builder.h"
34 
35 using ::grpc::ServerAsyncResponseWriter;
36 using ::grpc::ServerAsyncWriter;
37 using ::grpc::ServerContext;
38 
39 using ::bluetooth::packet::RawBuilder;
40 
41 namespace bluetooth {
42 namespace l2cap {
43 namespace classic {
44 
45 using namespace blueberry::facade::l2cap::classic;
46 
47 class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service, public LinkSecurityInterfaceListener {
48  public:
L2capClassicModuleFacadeService(L2capClassicModule * l2cap_layer,os::Handler * facade_handler)49   L2capClassicModuleFacadeService(L2capClassicModule* l2cap_layer, os::Handler* facade_handler)
50       : l2cap_layer_(l2cap_layer), facade_handler_(facade_handler), security_interface_(nullptr) {
51     log::assert_that(l2cap_layer_ != nullptr, "assert failed: l2cap_layer_ != nullptr");
52     log::assert_that(facade_handler_ != nullptr, "assert failed: facade_handler_ != nullptr");
53   }
54 
FetchConnectionComplete(::grpc::ServerContext * context,const::google::protobuf::Empty *,::grpc::ServerWriter<classic::ConnectionCompleteEvent> * writer)55   ::grpc::Status FetchConnectionComplete(
56       ::grpc::ServerContext* context,
57       const ::google::protobuf::Empty* /* request */,
58       ::grpc::ServerWriter<classic::ConnectionCompleteEvent>* writer) override {
59     return pending_connection_complete_.RunLoop(context, writer);
60   }
61 
FetchConnectionClose(::grpc::ServerContext * context,const::google::protobuf::Empty *,::grpc::ServerWriter<classic::ConnectionCloseEvent> * writer)62   ::grpc::Status FetchConnectionClose(
63       ::grpc::ServerContext* context,
64       const ::google::protobuf::Empty* /* request */,
65       ::grpc::ServerWriter<classic::ConnectionCloseEvent>* writer) override {
66     return pending_connection_close_.RunLoop(context, writer);
67   }
68 
SendDynamicChannelPacket(::grpc::ServerContext *,const DynamicChannelPacket * request,::google::protobuf::Empty *)69   ::grpc::Status SendDynamicChannelPacket(
70       ::grpc::ServerContext* /* context */,
71       const DynamicChannelPacket* request,
72       ::google::protobuf::Empty* /* response */) override {
73     std::unique_lock<std::mutex> lock(channel_map_mutex_);
74     if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) {
75       return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered");
76     }
77     std::vector<uint8_t> packet(request->payload().begin(), request->payload().end());
78     if (!dynamic_channel_helper_map_[request->psm()]->SendPacket(packet)) {
79       return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Channel not open");
80     }
81     return ::grpc::Status::OK;
82   }
83 
OpenChannel(::grpc::ServerContext *,const::bluetooth::l2cap::classic::OpenChannelRequest * request,::google::protobuf::Empty *)84   ::grpc::Status OpenChannel(
85       ::grpc::ServerContext* /* context */,
86       const ::bluetooth::l2cap::classic::OpenChannelRequest* request,
87       ::google::protobuf::Empty* /* response */) override {
88     auto service_helper = dynamic_channel_helper_map_.find(request->psm());
89     if (service_helper == dynamic_channel_helper_map_.end()) {
90       return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered");
91     }
92     hci::Address peer;
93     log::assert_that(
94         hci::Address::FromString(request->remote().address(), peer),
95         "assert failed: hci::Address::FromString(request->remote().address(), peer)");
96     dynamic_channel_helper_map_[request->psm()]->Connect(peer);
97     return ::grpc::Status::OK;
98   }
99 
CloseChannel(::grpc::ServerContext *,const::bluetooth::l2cap::classic::CloseChannelRequest * request,::google::protobuf::Empty *)100   ::grpc::Status CloseChannel(
101       ::grpc::ServerContext* /* context */,
102       const ::bluetooth::l2cap::classic::CloseChannelRequest* request,
103       ::google::protobuf::Empty* /* response */) override {
104     auto psm = request->psm();
105     if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) {
106       return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered");
107     }
108     dynamic_channel_helper_map_[psm]->Disconnect();
109     return ::grpc::Status::OK;
110   }
111 
FetchL2capData(::grpc::ServerContext * context,const::google::protobuf::Empty *,::grpc::ServerWriter<classic::L2capPacket> * writer)112   ::grpc::Status FetchL2capData(
113       ::grpc::ServerContext* context,
114       const ::google::protobuf::Empty* /* request */,
115       ::grpc::ServerWriter<classic::L2capPacket>* writer) override {
116     auto status = pending_l2cap_data_.RunLoop(context, writer);
117 
118     return status;
119   }
120 
SetDynamicChannel(::grpc::ServerContext *,const SetEnableDynamicChannelRequest * request,google::protobuf::Empty *)121   ::grpc::Status SetDynamicChannel(
122       ::grpc::ServerContext* /* context */,
123       const SetEnableDynamicChannelRequest* request,
124       google::protobuf::Empty* /* response */) override {
125     dynamic_channel_helper_map_.emplace(
126         request->psm(), std::make_unique<L2capDynamicChannelHelper>(this, l2cap_layer_, facade_handler_, request->psm(),
127                                                                     request->retransmission_mode()));
128     return ::grpc::Status::OK;
129   }
130 
SetTrafficPaused(::grpc::ServerContext *,const SetTrafficPausedRequest * request,::google::protobuf::Empty *)131   ::grpc::Status SetTrafficPaused(
132       ::grpc::ServerContext* /* context */,
133       const SetTrafficPausedRequest* request,
134       ::google::protobuf::Empty* /* response */) override {
135     auto psm = request->psm();
136     if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) {
137       return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered");
138     }
139     if (request->paused()) {
140       dynamic_channel_helper_map_[psm]->SuspendDequeue();
141     } else {
142       dynamic_channel_helper_map_[psm]->ResumeDequeue();
143     }
144     return ::grpc::Status::OK;
145   }
146 
GetChannelQueueDepth(::grpc::ServerContext *,const::google::protobuf::Empty *,GetChannelQueueDepthResponse * response)147   ::grpc::Status GetChannelQueueDepth(
148       ::grpc::ServerContext* /* context */,
149       const ::google::protobuf::Empty* /* request */,
150       GetChannelQueueDepthResponse* response) override {
151     // Use the value kChannelQueueSize (5) in internal/dynamic_channel_impl.h
152     response->set_size(5);
153     return ::grpc::Status::OK;
154   }
155 
InitiateConnectionForSecurity(::grpc::ServerContext *,const blueberry::facade::BluetoothAddress * request,::google::protobuf::Empty *)156   ::grpc::Status InitiateConnectionForSecurity(
157       ::grpc::ServerContext* /* context */,
158       const blueberry::facade::BluetoothAddress* request,
159       ::google::protobuf::Empty* /* response */) override {
160     hci::Address peer;
161     log::assert_that(
162         hci::Address::FromString(request->address(), peer),
163         "assert failed: hci::Address::FromString(request->address(), peer)");
164     outgoing_pairing_remote_devices_.insert(peer);
165     security_interface_->InitiateConnectionForSecurity(peer);
166     return ::grpc::Status::OK;
167   }
168 
SecurityConnectionEventOccurred(hci::ErrorCode,hci::Address remote,LinkSecurityInterfaceCallbackEventType event_type)169   void SecurityConnectionEventOccurred(
170       hci::ErrorCode /* hci_status */,
171       hci::Address remote,
172       LinkSecurityInterfaceCallbackEventType event_type) {
173     LinkSecurityInterfaceCallbackEvent msg;
174     msg.mutable_address()->set_address(remote.ToString());
175     msg.set_event_type(event_type);
176     security_connection_events_.OnIncomingEvent(msg);
177   }
178 
FetchSecurityConnectionEvents(::grpc::ServerContext * context,const::google::protobuf::Empty *,::grpc::ServerWriter<LinkSecurityInterfaceCallbackEvent> * writer)179   ::grpc::Status FetchSecurityConnectionEvents(
180       ::grpc::ServerContext* context,
181       const ::google::protobuf::Empty* /* request */,
182       ::grpc::ServerWriter<LinkSecurityInterfaceCallbackEvent>* writer) override {
183     security_interface_ = l2cap_layer_->GetSecurityInterface(facade_handler_, this);
184     return security_connection_events_.RunLoop(context, writer);
185   }
186 
SecurityLinkHold(::grpc::ServerContext *,const blueberry::facade::BluetoothAddress * request,::google::protobuf::Empty *)187   ::grpc::Status SecurityLinkHold(
188       ::grpc::ServerContext* /* context */,
189       const blueberry::facade::BluetoothAddress* request,
190       ::google::protobuf::Empty* /* response */) override {
191     hci::Address peer;
192     log::assert_that(
193         hci::Address::FromString(request->address(), peer),
194         "assert failed: hci::Address::FromString(request->address(), peer)");
195     auto entry = security_link_map_.find(peer);
196     if (entry == security_link_map_.end()) {
197       log::warn("Unknown address '{}'", peer);
198     } else {
199       entry->second->Hold();
200     }
201     return ::grpc::Status::OK;
202   }
203 
SecurityLinkEnsureAuthenticated(::grpc::ServerContext *,const blueberry::facade::BluetoothAddress * request,::google::protobuf::Empty *)204   ::grpc::Status SecurityLinkEnsureAuthenticated(
205       ::grpc::ServerContext* /* context */,
206       const blueberry::facade::BluetoothAddress* request,
207       ::google::protobuf::Empty* /* response */) override {
208     hci::Address peer;
209     log::assert_that(
210         hci::Address::FromString(request->address(), peer),
211         "assert failed: hci::Address::FromString(request->address(), peer)");
212     auto entry = security_link_map_.find(peer);
213     if (entry == security_link_map_.end()) {
214       log::warn("Unknown address '{}'", peer);
215     } else {
216       entry->second->EnsureAuthenticated();
217     }
218     return ::grpc::Status::OK;
219   }
220 
SecurityLinkRelease(::grpc::ServerContext *,const blueberry::facade::BluetoothAddress * request,::google::protobuf::Empty *)221   ::grpc::Status SecurityLinkRelease(
222       ::grpc::ServerContext* /* context */,
223       const blueberry::facade::BluetoothAddress* request,
224       ::google::protobuf::Empty* /* response */) override {
225     hci::Address peer;
226     log::assert_that(
227         hci::Address::FromString(request->address(), peer),
228         "assert failed: hci::Address::FromString(request->address(), peer)");
229     outgoing_pairing_remote_devices_.erase(peer);
230     auto entry = security_link_map_.find(peer);
231     if (entry == security_link_map_.end()) {
232       log::warn("Unknown address '{}'", peer);
233     } else {
234       entry->second->Release();
235     }
236     return ::grpc::Status::OK;
237   }
238 
SecurityLinkDisconnect(::grpc::ServerContext *,const blueberry::facade::BluetoothAddress * request,::google::protobuf::Empty *)239   ::grpc::Status SecurityLinkDisconnect(
240       ::grpc::ServerContext* /* context */,
241       const blueberry::facade::BluetoothAddress* request,
242       ::google::protobuf::Empty* /* response */) override {
243     hci::Address peer;
244     log::assert_that(
245         hci::Address::FromString(request->address(), peer),
246         "assert failed: hci::Address::FromString(request->address(), peer)");
247     outgoing_pairing_remote_devices_.erase(peer);
248     auto entry = security_link_map_.find(peer);
249     if (entry == security_link_map_.end()) {
250       log::warn("Unknown address '{}'", peer);
251     } else {
252       entry->second->Disconnect();
253     }
254     return ::grpc::Status::OK;
255   }
256 
OnLinkConnected(std::unique_ptr<LinkSecurityInterface> link)257   void OnLinkConnected(std::unique_ptr<LinkSecurityInterface> link) override {
258     auto remote = link->GetRemoteAddress();
259     if (outgoing_pairing_remote_devices_.count(remote) == 1) {
260       link->Hold();
261       link->EnsureAuthenticated();
262       outgoing_pairing_remote_devices_.erase(remote);
263     }
264     security_link_map_.emplace(remote, std::move(link));
265     SecurityConnectionEventOccurred(
266         hci::ErrorCode::SUCCESS, remote, LinkSecurityInterfaceCallbackEventType::ON_CONNECTED);
267   }
268 
OnLinkDisconnected(hci::Address remote)269   void OnLinkDisconnected(hci::Address remote) override {
270     auto entry = security_link_map_.find(remote);
271     if (entry == security_link_map_.end()) {
272       log::warn("Unknown address '{}'", remote);
273       return;
274     }
275     entry->second.reset();
276     security_link_map_.erase(entry);
277     SecurityConnectionEventOccurred(
278         hci::ErrorCode::SUCCESS, remote, LinkSecurityInterfaceCallbackEventType::ON_DISCONNECTED);
279   }
280 
OnAuthenticationComplete(hci::ErrorCode hci_status,hci::Address remote)281   void OnAuthenticationComplete(hci::ErrorCode hci_status, hci::Address remote) override {
282     auto entry = security_link_map_.find(remote);
283     if (entry != security_link_map_.end()) {
284       entry->second->EnsureEncrypted();
285       return;
286     }
287     SecurityConnectionEventOccurred(
288         hci_status, remote, LinkSecurityInterfaceCallbackEventType::ON_AUTHENTICATION_COMPLETE);
289   }
290 
OnEncryptionChange(hci::Address remote,bool)291   void OnEncryptionChange(hci::Address remote, bool /* encrypted */) override {
292     SecurityConnectionEventOccurred(
293         hci::ErrorCode::SUCCESS, remote, LinkSecurityInterfaceCallbackEventType::ON_ENCRYPTION_CHANGE);
294   }
295 
296   class L2capDynamicChannelHelper {
297    public:
L2capDynamicChannelHelper(L2capClassicModuleFacadeService * service,L2capClassicModule * l2cap_layer,os::Handler * handler,Psm psm,RetransmissionFlowControlMode mode)298     L2capDynamicChannelHelper(L2capClassicModuleFacadeService* service, L2capClassicModule* l2cap_layer,
299                               os::Handler* handler, Psm psm, RetransmissionFlowControlMode mode)
300         : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm), mode_(mode) {
301       dynamic_channel_manager_ = l2cap_layer_->GetDynamicChannelManager();
302       DynamicChannelConfigurationOption configuration_option = {};
303       configuration_option.channel_mode = (DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode)mode;
304       dynamic_channel_manager_->RegisterService(
305           psm,
306           configuration_option,
307           SecurityPolicy::_SDP_ONLY_NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK,
308           handler_->BindOnceOn(this, &L2capDynamicChannelHelper::on_l2cap_service_registration_complete),
309           handler_->BindOn(this, &L2capDynamicChannelHelper::on_connection_open));
310     }
311 
~L2capDynamicChannelHelper()312     ~L2capDynamicChannelHelper() {
313       if (dequeue_registered_) {
314         channel_->GetQueueUpEnd()->UnregisterDequeue();
315         channel_ = nullptr;
316       }
317       enqueue_buffer_.reset();
318     }
319 
Connect(hci::Address address)320     void Connect(hci::Address address) {
321       DynamicChannelConfigurationOption configuration_option = l2cap::classic::DynamicChannelConfigurationOption();
322       configuration_option.channel_mode = (DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode)mode_;
323 
324       dynamic_channel_manager_->ConnectChannel(
325           address,
326           configuration_option,
327           psm_,
328           handler_->BindOn(this, &L2capDynamicChannelHelper::on_connection_open),
329           handler_->BindOnceOn(this, &L2capDynamicChannelHelper::on_connect_fail));
330       std::unique_lock<std::mutex> lock(channel_open_cv_mutex_);
331       if (!channel_open_cv_.wait_for(lock, std::chrono::seconds(2), [this] { return channel_ != nullptr; })) {
332         log::warn("Channel is not open for psm {}", psm_);
333       }
334     }
335 
Disconnect()336     void Disconnect() {
337       if (channel_ == nullptr) {
338         std::unique_lock<std::mutex> lock(channel_open_cv_mutex_);
339         if (!channel_open_cv_.wait_for(lock, std::chrono::seconds(2), [this] { return channel_ != nullptr; })) {
340           log::warn("Channel is not open for psm {}", psm_);
341           return;
342         }
343       }
344       channel_->Close();
345     }
346 
on_l2cap_service_registration_complete(DynamicChannelManager::RegistrationResult,std::unique_ptr<DynamicChannelService>)347     void on_l2cap_service_registration_complete(
348         DynamicChannelManager::RegistrationResult /* registration_result */,
349         std::unique_ptr<DynamicChannelService> /* service */) {}
350 
351     // invoked from Facade Handler
on_connection_open(std::unique_ptr<DynamicChannel> channel)352     void on_connection_open(std::unique_ptr<DynamicChannel> channel) {
353       ConnectionCompleteEvent event;
354       event.mutable_remote()->set_address(channel->GetDevice().GetAddress().ToString());
355       facade_service_->pending_connection_complete_.OnIncomingEvent(event);
356       {
357         std::unique_lock<std::mutex> lock(channel_open_cv_mutex_);
358         channel_ = std::move(channel);
359         enqueue_buffer_ = std::make_unique<os::EnqueueBuffer<BasePacketBuilder>>(channel_->GetQueueUpEnd());
360       }
361       channel_open_cv_.notify_all();
362       channel_->RegisterOnCloseCallback(
363           facade_service_->facade_handler_->BindOnceOn(this, &L2capDynamicChannelHelper::on_close_callback));
364       dequeue_registered_ = true;
365       channel_->GetQueueUpEnd()->RegisterDequeue(
366           facade_service_->facade_handler_,
367           common::Bind(&L2capDynamicChannelHelper::on_incoming_packet, common::Unretained(this)));
368     }
369 
on_close_callback(hci::ErrorCode error_code)370     void on_close_callback(hci::ErrorCode error_code) {
371       {
372         std::unique_lock<std::mutex> lock(channel_open_cv_mutex_);
373         if (dequeue_registered_.exchange(false)) {
374           channel_->GetQueueUpEnd()->UnregisterDequeue();
375         }
376       }
377       classic::ConnectionCloseEvent event;
378       event.mutable_remote()->set_address(channel_->GetDevice().GetAddress().ToString());
379       event.set_reason(static_cast<uint32_t>(error_code));
380       facade_service_->pending_connection_close_.OnIncomingEvent(event);
381       channel_ = nullptr;
382       enqueue_buffer_.reset();
383     }
384 
SuspendDequeue()385     void SuspendDequeue() {
386       if (dequeue_registered_.exchange(false)) {
387         channel_->GetQueueUpEnd()->UnregisterDequeue();
388       }
389     }
390 
ResumeDequeue()391     void ResumeDequeue() {
392       if (!dequeue_registered_.exchange(true)) {
393         channel_->GetQueueUpEnd()->RegisterDequeue(
394             facade_service_->facade_handler_,
395             common::Bind(&L2capDynamicChannelHelper::on_incoming_packet, common::Unretained(this)));
396       }
397     }
398 
on_connect_fail(DynamicChannelManager::ConnectionResult)399     void on_connect_fail(DynamicChannelManager::ConnectionResult /* result */) {}
400 
on_incoming_packet()401     void on_incoming_packet() {
402       auto packet = channel_->GetQueueUpEnd()->TryDequeue();
403       std::string data = std::string(packet->begin(), packet->end());
404       L2capPacket l2cap_data;
405       l2cap_data.set_psm(psm_);
406       l2cap_data.set_payload(data);
407       facade_service_->pending_l2cap_data_.OnIncomingEvent(l2cap_data);
408     }
409 
SendPacket(std::vector<uint8_t> packet)410     bool SendPacket(std::vector<uint8_t> packet) {
411       if (channel_ == nullptr) {
412         std::unique_lock<std::mutex> lock(channel_open_cv_mutex_);
413         if (!channel_open_cv_.wait_for(lock, std::chrono::seconds(2), [this] { return channel_ != nullptr; })) {
414           log::warn("Channel is not open");
415           return false;
416         }
417       }
418       auto packet_one = std::make_unique<packet::RawBuilder>(2000);
419       packet_one->AddOctets(packet);
420       enqueue_buffer_->Enqueue(std::move(packet_one), handler_);
421       return true;
422     }
423     L2capClassicModuleFacadeService* facade_service_;
424     L2capClassicModule* l2cap_layer_;
425     os::Handler* handler_;
426     std::unique_ptr<DynamicChannelManager> dynamic_channel_manager_;
427     std::unique_ptr<DynamicChannelService> service_;
428     std::unique_ptr<DynamicChannel> channel_ = nullptr;
429     std::unique_ptr<os::EnqueueBuffer<BasePacketBuilder>> enqueue_buffer_ = nullptr;
430     Psm psm_;
431     RetransmissionFlowControlMode mode_ = RetransmissionFlowControlMode::BASIC;
432     std::atomic_bool dequeue_registered_ = false;
433     std::condition_variable channel_open_cv_;
434     std::mutex channel_open_cv_mutex_;
435   };
436 
437   L2capClassicModule* l2cap_layer_;
438   ::bluetooth::os::Handler* facade_handler_;
439   std::mutex channel_map_mutex_;
440   std::map<Psm, std::unique_ptr<L2capDynamicChannelHelper>> dynamic_channel_helper_map_;
441   ::bluetooth::grpc::GrpcEventQueue<classic::ConnectionCompleteEvent> pending_connection_complete_{
442       "FetchConnectionComplete"};
443   ::bluetooth::grpc::GrpcEventQueue<classic::ConnectionCloseEvent> pending_connection_close_{"FetchConnectionClose"};
444   ::bluetooth::grpc::GrpcEventQueue<L2capPacket> pending_l2cap_data_{"FetchL2capData"};
445   ::bluetooth::grpc::GrpcEventQueue<LinkSecurityInterfaceCallbackEvent> security_connection_events_{
446       "Security Connection Events"};
447   SecurityInterface* security_interface_;
448   std::unordered_map<hci::Address, std::unique_ptr<l2cap::classic::LinkSecurityInterface>> security_link_map_;
449   std::set<hci::Address> outgoing_pairing_remote_devices_;
450 };
451 
ListDependencies(ModuleList * list) const452 void L2capClassicModuleFacadeModule::ListDependencies(ModuleList* list) const {
453   ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
454   list->add<l2cap::classic::L2capClassicModule>();
455 }
456 
Start()457 void L2capClassicModuleFacadeModule::Start() {
458   ::bluetooth::grpc::GrpcFacadeModule::Start();
459   service_ = new L2capClassicModuleFacadeService(GetDependency<l2cap::classic::L2capClassicModule>(), GetHandler());
460 }
461 
Stop()462 void L2capClassicModuleFacadeModule::Stop() {
463   delete service_;
464   ::bluetooth::grpc::GrpcFacadeModule::Stop();
465 }
466 
GetService() const467 ::grpc::Service* L2capClassicModuleFacadeModule::GetService() const {
468   return service_;
469 }
470 
471 const ModuleFactory L2capClassicModuleFacadeModule::Factory =
__anonbd297ca20402() 472     ::bluetooth::ModuleFactory([]() { return new L2capClassicModuleFacadeModule(); });
473 
474 }  // namespace classic
475 }  // namespace l2cap
476 }  // namespace bluetooth
477