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/ipc/binder/bluetooth_low_energy_binder_server.h"
18
19#include <base/logging.h>
20
21#include "service/adapter.h"
22
23namespace ipc {
24namespace binder {
25
26namespace {
27const int kInvalidInstanceId = -1;
28}  // namespace
29
30BluetoothLowEnergyBinderServer::BluetoothLowEnergyBinderServer(
31    bluetooth::Adapter* adapter) : adapter_(adapter) {
32  CHECK(adapter_);
33}
34
35BluetoothLowEnergyBinderServer::~BluetoothLowEnergyBinderServer() {
36}
37
38bool BluetoothLowEnergyBinderServer::RegisterClient(
39    const android::sp<IBluetoothLowEnergyCallback>& callback) {
40  VLOG(2) << __func__;
41  bluetooth::LowEnergyClientFactory* ble_factory =
42      adapter_->GetLowEnergyClientFactory();
43
44  return RegisterInstanceBase(callback, ble_factory);
45}
46
47void BluetoothLowEnergyBinderServer::UnregisterClient(int client_id) {
48  VLOG(2) << __func__;
49  UnregisterInstanceBase(client_id);
50}
51
52void BluetoothLowEnergyBinderServer::UnregisterAll() {
53  VLOG(2) << __func__;
54  UnregisterAllBase();
55}
56
57bool BluetoothLowEnergyBinderServer::Connect(int client_id,
58                                             const char* address,
59                                             bool is_direct) {
60  VLOG(2) << __func__ << " client_id: " << client_id
61          << " address: " << address
62          << " is_direct: " << is_direct;
63  std::lock_guard<std::mutex> lock(*maps_lock());
64
65  auto client = GetLEClient(client_id);
66  if (!client) {
67    LOG(ERROR) << "Unknown client_id: " << client_id;
68    return false;
69  }
70
71  return client->Connect(std::string(address), is_direct);
72}
73
74bool BluetoothLowEnergyBinderServer::Disconnect(int client_id,
75                                                const char* address) {
76  VLOG(2) << __func__ << " client_id: " << client_id
77          << " address: " << address;
78  std::lock_guard<std::mutex> lock(*maps_lock());
79
80  auto client = GetLEClient(client_id);
81  if (!client) {
82    LOG(ERROR) << "Unknown client_id: " << client_id;
83    return false;
84  }
85
86  return client->Disconnect(std::string(address));
87}
88
89bool BluetoothLowEnergyBinderServer::SetMtu(int client_id,
90                                            const char* address,
91                                            int mtu) {
92  VLOG(2) << __func__ << " client_id: " << client_id
93          << " address: " << address
94          << " mtu: " << mtu;
95  std::lock_guard<std::mutex> lock(*maps_lock());
96
97  auto client = GetLEClient(client_id);
98  if (!client) {
99    LOG(ERROR) << "Unknown client_id: " << client_id;
100    return false;
101  }
102
103  return client->SetMtu(address, mtu);
104}
105
106bool BluetoothLowEnergyBinderServer::StartScan(
107    int client_id,
108    const bluetooth::ScanSettings& settings,
109    const std::vector<bluetooth::ScanFilter>& filters) {
110  VLOG(2) << __func__ << " client_id: " << client_id;
111  std::lock_guard<std::mutex> lock(*maps_lock());
112
113  auto client = GetLEClient(client_id);
114  if (!client) {
115    LOG(ERROR) << "Unknown client_id: " << client_id;
116    return false;
117  }
118
119  return client->StartScan(settings, filters);
120}
121
122bool BluetoothLowEnergyBinderServer::StopScan(int client_id) {
123  VLOG(2) << __func__ << " client_id: " << client_id;
124  std::lock_guard<std::mutex> lock(*maps_lock());
125
126  auto client = GetLEClient(client_id);
127  if (!client) {
128    LOG(ERROR) << "Unknown client_id: " << client_id;
129    return false;
130  }
131
132  return client->StopScan();
133}
134
135bool BluetoothLowEnergyBinderServer::StartMultiAdvertising(
136    int client_id,
137    const bluetooth::AdvertiseData& advertise_data,
138    const bluetooth::AdvertiseData& scan_response,
139    const bluetooth::AdvertiseSettings& settings) {
140  VLOG(2) << __func__ << " client_id: " << client_id;
141  std::lock_guard<std::mutex> lock(*maps_lock());
142
143  auto client = GetLEClient(client_id);
144  if (!client) {
145    LOG(ERROR) << "Unknown client_id: " << client_id;
146    return false;
147  }
148
149  // Create a weak pointer and pass that to the callback to prevent a potential
150  // use after free.
151  android::wp<BluetoothLowEnergyBinderServer> weak_ptr_to_this(this);
152  auto settings_copy = settings;
153  auto callback = [=](bluetooth::BLEStatus status) {
154    auto sp_to_this = weak_ptr_to_this.promote();
155    if (!sp_to_this.get()) {
156      VLOG(2) << "BluetoothLowEnergyBinderServer was deleted";
157      return;
158    }
159
160    std::lock_guard<std::mutex> lock(*maps_lock());
161
162    auto cb = GetLECallback(client_id);
163    if (!cb.get()) {
164      VLOG(1) << "Client was removed before callback: " << client_id;
165      return;
166    }
167
168    cb->OnMultiAdvertiseCallback(status, true /* is_start */, settings_copy);
169  };
170
171  if (!client->StartAdvertising(
172      settings, advertise_data, scan_response, callback)) {
173    LOG(ERROR) << "Failed to initiate call to start advertising";
174    return false;
175  }
176
177  return true;
178}
179
180bool BluetoothLowEnergyBinderServer::StopMultiAdvertising(int client_id) {
181  VLOG(2) << __func__;
182  std::lock_guard<std::mutex> lock(*maps_lock());
183
184  auto client = GetLEClient(client_id);
185  if (!client) {
186    LOG(ERROR) << "Unknown client_id: " << client_id;
187    return false;
188  }
189
190  // Create a weak pointer and pass that to the callback to prevent a potential
191  // use after free.
192  android::wp<BluetoothLowEnergyBinderServer> weak_ptr_to_this(this);
193  auto settings_copy = client->advertise_settings();
194  auto callback = [=](bluetooth::BLEStatus status) {
195    auto sp_to_this = weak_ptr_to_this.promote();
196    if (!sp_to_this.get()) {
197      VLOG(2) << "BluetoothLowEnergyBinderServer was deleted";
198      return;
199    }
200
201    auto cb = GetLECallback(client_id);
202    if (!cb.get()) {
203      VLOG(2) << "Client was unregistered - client_id: " << client_id;
204      return;
205    }
206
207    std::lock_guard<std::mutex> lock(*maps_lock());
208
209    cb->OnMultiAdvertiseCallback(status, false /* is_start */, settings_copy);
210  };
211
212  if (!client->StopAdvertising(callback)) {
213    LOG(ERROR) << "Failed to initiate call to start advertising";
214    return false;
215  }
216
217  return true;
218}
219
220void BluetoothLowEnergyBinderServer::OnConnectionState(
221      bluetooth::LowEnergyClient* client, int status,
222      const char* address, bool connected) {
223  VLOG(2) << __func__ << " address: " << address << " connected: " << connected;
224
225  int client_id = client->GetInstanceId();
226  auto cb = GetLECallback(client->GetInstanceId());
227  if (!cb.get()) {
228    VLOG(2) << "Client was unregistered - client_id: " << client_id;
229    return;
230  }
231
232  cb->OnConnectionState(status, client_id, address, connected);
233}
234
235void BluetoothLowEnergyBinderServer::OnMtuChanged(
236      bluetooth::LowEnergyClient* client, int status, const char* address, int mtu) {
237  VLOG(2) << __func__ << " address: " << address
238          << " status: " << status
239          << " mtu: " << mtu;
240
241  int client_id = client->GetInstanceId();
242  auto cb = GetLECallback(client_id);
243  if (!cb.get()) {
244    VLOG(2) << "Client was unregistered - client_id: " << client_id;
245    return;
246  }
247
248  cb->OnMtuChanged(status, address, mtu);
249}
250
251void BluetoothLowEnergyBinderServer::OnScanResult(
252    bluetooth::LowEnergyClient* client,
253    const bluetooth::ScanResult& result) {
254  VLOG(2) << __func__;
255  std::lock_guard<std::mutex> lock(*maps_lock());
256
257  int client_id = client->GetInstanceId();
258  auto cb = GetLECallback(client->GetInstanceId());
259  if (!cb.get()) {
260    VLOG(2) << "Client was unregistered - client_id: " << client_id;
261    return;
262  }
263
264  cb->OnScanResult(result);
265}
266
267android::sp<IBluetoothLowEnergyCallback>
268BluetoothLowEnergyBinderServer::GetLECallback(int client_id) {
269  auto cb = GetCallback(client_id);
270  return android::sp<IBluetoothLowEnergyCallback>(
271      static_cast<IBluetoothLowEnergyCallback*>(cb.get()));
272}
273
274std::shared_ptr<bluetooth::LowEnergyClient>
275BluetoothLowEnergyBinderServer::GetLEClient(int client_id) {
276  return std::static_pointer_cast<bluetooth::LowEnergyClient>(
277      GetInstance(client_id));
278}
279
280void BluetoothLowEnergyBinderServer::OnRegisterInstanceImpl(
281    bluetooth::BLEStatus status,
282    android::sp<IInterface> callback,
283    bluetooth::BluetoothInstance* instance) {
284  VLOG(1) << __func__ << " status: " << status;
285  bluetooth::LowEnergyClient* le_client =
286      static_cast<bluetooth::LowEnergyClient*>(instance);
287  le_client->SetDelegate(this);
288
289  android::sp<IBluetoothLowEnergyCallback> cb(
290      static_cast<IBluetoothLowEnergyCallback*>(callback.get()));
291  cb->OnClientRegistered(
292      status,
293      (status == bluetooth::BLE_STATUS_SUCCESS) ?
294          instance->GetInstanceId() : kInvalidInstanceId);
295}
296
297}  // namespace binder
298}  // namespace ipc
299