1 //
2 //  Copyright (C) 2015 Google, Inc.
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 "service/low_energy_client.h"
18 
19 #include <base/logging.h>
20 
21 #include "service/adapter.h"
22 #include "service/common/bluetooth/util/address_helper.h"
23 #include "service/logging_helpers.h"
24 #include "stack/include/bt_types.h"
25 #include "stack/include/hcidefs.h"
26 
27 using std::lock_guard;
28 using std::mutex;
29 
30 namespace bluetooth {
31 
32 // LowEnergyClient implementation
33 // ========================================================
34 
LowEnergyClient(Adapter & adapter,const UUID & uuid,int client_id)35 LowEnergyClient::LowEnergyClient(Adapter& adapter, const UUID& uuid,
36                                  int client_id)
37     : adapter_(adapter),
38       app_identifier_(uuid),
39       client_id_(client_id),
40       delegate_(nullptr) {}
41 
~LowEnergyClient()42 LowEnergyClient::~LowEnergyClient() {
43   // Automatically unregister the client.
44   VLOG(1) << "LowEnergyClient unregistering client: " << client_id_;
45 
46   // Unregister as observer so we no longer receive any callbacks.
47   hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
48 
49   hal::BluetoothGattInterface::Get()
50       ->GetClientHALInterface()
51       ->unregister_client(client_id_);
52 }
53 
Connect(const std::string & address,bool is_direct)54 bool LowEnergyClient::Connect(const std::string& address, bool is_direct) {
55   VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct;
56 
57   bt_bdaddr_t bda;
58   util::BdAddrFromString(address, &bda);
59 
60   bt_status_t status =
61       hal::BluetoothGattInterface::Get()->GetClientHALInterface()->connect(
62           client_id_, &bda, is_direct, BT_TRANSPORT_LE, PHY_LE_1M_MASK);
63   if (status != BT_STATUS_SUCCESS) {
64     LOG(ERROR) << "HAL call to connect failed";
65     return false;
66   }
67 
68   return true;
69 }
70 
Disconnect(const std::string & address)71 bool LowEnergyClient::Disconnect(const std::string& address) {
72   VLOG(2) << __func__ << "Address: " << address;
73 
74   bt_bdaddr_t bda;
75   util::BdAddrFromString(address, &bda);
76 
77   std::map<const bt_bdaddr_t, int>::iterator conn_id;
78   {
79     lock_guard<mutex> lock(connection_fields_lock_);
80     conn_id = connection_ids_.find(bda);
81     if (conn_id == connection_ids_.end()) {
82       LOG(WARNING) << "Can't disconnect, no existing connection to " << address;
83       return false;
84     }
85   }
86 
87   bt_status_t status =
88       hal::BluetoothGattInterface::Get()->GetClientHALInterface()->disconnect(
89           client_id_, &bda, conn_id->second);
90   if (status != BT_STATUS_SUCCESS) {
91     LOG(ERROR) << "HAL call to disconnect failed";
92     return false;
93   }
94 
95   return true;
96 }
97 
SetMtu(const std::string & address,int mtu)98 bool LowEnergyClient::SetMtu(const std::string& address, int mtu) {
99   VLOG(2) << __func__ << "Address: " << address << " MTU: " << mtu;
100 
101   bt_bdaddr_t bda;
102   util::BdAddrFromString(address, &bda);
103 
104   std::map<const bt_bdaddr_t, int>::iterator conn_id;
105   {
106     lock_guard<mutex> lock(connection_fields_lock_);
107     conn_id = connection_ids_.find(bda);
108     if (conn_id == connection_ids_.end()) {
109       LOG(WARNING) << "Can't set MTU, no existing connection to " << address;
110       return false;
111     }
112   }
113 
114   bt_status_t status = hal::BluetoothGattInterface::Get()
115                            ->GetClientHALInterface()
116                            ->configure_mtu(conn_id->second, mtu);
117   if (status != BT_STATUS_SUCCESS) {
118     LOG(ERROR) << "HAL call to set MTU failed";
119     return false;
120   }
121 
122   return true;
123 }
124 
SetDelegate(Delegate * delegate)125 void LowEnergyClient::SetDelegate(Delegate* delegate) {
126   lock_guard<mutex> lock(delegate_mutex_);
127   delegate_ = delegate;
128 }
129 
GetAppIdentifier() const130 const UUID& LowEnergyClient::GetAppIdentifier() const {
131   return app_identifier_;
132 }
133 
GetInstanceId() const134 int LowEnergyClient::GetInstanceId() const { return client_id_; }
135 
ConnectCallback(hal::BluetoothGattInterface * gatt_iface,int conn_id,int status,int client_id,const bt_bdaddr_t & bda)136 void LowEnergyClient::ConnectCallback(hal::BluetoothGattInterface* gatt_iface,
137                                       int conn_id, int status, int client_id,
138                                       const bt_bdaddr_t& bda) {
139   if (client_id != client_id_) return;
140 
141   VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
142 
143   {
144     lock_guard<mutex> lock(connection_fields_lock_);
145     auto success = connection_ids_.emplace(bda, conn_id);
146     if (!success.second) {
147       LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!";
148     }
149   }
150 
151   if (delegate_)
152     delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
153                                  true);
154 }
155 
DisconnectCallback(hal::BluetoothGattInterface * gatt_iface,int conn_id,int status,int client_id,const bt_bdaddr_t & bda)156 void LowEnergyClient::DisconnectCallback(
157     hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
158     int client_id, const bt_bdaddr_t& bda) {
159   if (client_id != client_id_) return;
160 
161   VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status;
162   {
163     lock_guard<mutex> lock(connection_fields_lock_);
164     if (!connection_ids_.erase(bda)) {
165       LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!";
166     }
167   }
168 
169   if (delegate_)
170     delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
171                                  false);
172 }
173 
MtuChangedCallback(hal::BluetoothGattInterface * gatt_iface,int conn_id,int status,int mtu)174 void LowEnergyClient::MtuChangedCallback(
175     hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, int mtu) {
176   VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status
177           << " mtu: " << mtu;
178 
179   const bt_bdaddr_t* bda = nullptr;
180   {
181     lock_guard<mutex> lock(connection_fields_lock_);
182     for (auto& connection : connection_ids_) {
183       if (connection.second == conn_id) {
184         bda = &connection.first;
185         break;
186       }
187     }
188   }
189 
190   if (!bda) return;
191 
192   const char* addr = BtAddrString(bda).c_str();
193   if (delegate_) delegate_->OnMtuChanged(this, status, addr, mtu);
194 }
195 
196 // LowEnergyClientFactory implementation
197 // ========================================================
198 
LowEnergyClientFactory(Adapter & adapter)199 LowEnergyClientFactory::LowEnergyClientFactory(Adapter& adapter)
200     : adapter_(adapter) {
201   hal::BluetoothGattInterface::Get()->AddClientObserver(this);
202 }
203 
~LowEnergyClientFactory()204 LowEnergyClientFactory::~LowEnergyClientFactory() {
205   hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
206 }
207 
RegisterInstance(const UUID & uuid,const RegisterCallback & callback)208 bool LowEnergyClientFactory::RegisterInstance(
209     const UUID& uuid, const RegisterCallback& callback) {
210   VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
211   lock_guard<mutex> lock(pending_calls_lock_);
212 
213   if (pending_calls_.find(uuid) != pending_calls_.end()) {
214     LOG(ERROR) << "Low-Energy client with given UUID already registered - "
215                << "UUID: " << uuid.ToString();
216     return false;
217   }
218 
219   const btgatt_client_interface_t* hal_iface =
220       hal::BluetoothGattInterface::Get()->GetClientHALInterface();
221   bt_uuid_t app_uuid = uuid.GetBlueDroid();
222 
223   if (hal_iface->register_client(&app_uuid) != BT_STATUS_SUCCESS) return false;
224 
225   pending_calls_[uuid] = callback;
226 
227   return true;
228 }
229 
RegisterClientCallback(hal::BluetoothGattInterface * gatt_iface,int status,int client_id,const bt_uuid_t & app_uuid)230 void LowEnergyClientFactory::RegisterClientCallback(
231     hal::BluetoothGattInterface* gatt_iface, int status, int client_id,
232     const bt_uuid_t& app_uuid) {
233   UUID uuid(app_uuid);
234 
235   VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
236   lock_guard<mutex> lock(pending_calls_lock_);
237 
238   auto iter = pending_calls_.find(uuid);
239   if (iter == pending_calls_.end()) {
240     VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
241     return;
242   }
243 
244   // No need to construct a client if the call wasn't successful.
245   std::unique_ptr<LowEnergyClient> client;
246   BLEStatus result = BLE_STATUS_FAILURE;
247   if (status == BT_STATUS_SUCCESS) {
248     client.reset(new LowEnergyClient(adapter_, uuid, client_id));
249 
250     gatt_iface->AddClientObserver(client.get());
251 
252     result = BLE_STATUS_SUCCESS;
253   }
254 
255   // Notify the result via the result callback.
256   iter->second(result, uuid, std::move(client));
257 
258   pending_calls_.erase(iter);
259 }
260 
261 }  // namespace bluetooth
262