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