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 #include <base/bind.h>
17 #include <base/location.h>
18 #include <base/logging.h>
19 #include <base/rand_util.h>
20
21 #include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h>
22 #include <android/bluetooth/IBluetoothLeAdvertiser.h>
23 #include <bluetooth/low_energy_constants.h>
24
25 #include "constants.h"
26 #include "heart_rate_server.h"
27
28 using android::binder::Status;
29 using android::String8;
30 using android::String16;
31
32 using android::bluetooth::IBluetoothLeAdvertiser;
33 using android::bluetooth::BluetoothGattService;
34
35 namespace heart_rate {
36
37 class CLIBluetoothLeAdvertiserCallback
38 : public android::bluetooth::BnBluetoothLeAdvertiserCallback {
39 public:
CLIBluetoothLeAdvertiserCallback(android::sp<android::bluetooth::IBluetooth> bt)40 explicit CLIBluetoothLeAdvertiserCallback(
41 android::sp<android::bluetooth::IBluetooth> bt)
42 : bt_(bt) {}
43
44 // IBluetoothLeAdvertiserCallback overrides:
OnAdvertiserRegistered(int status,int advertiser_id)45 Status OnAdvertiserRegistered(int status, int advertiser_id) {
46 if (status != bluetooth::BLE_STATUS_SUCCESS) {
47 LOG(ERROR)
48 << "Failed to register BLE advertiser, will not start advertising";
49 return Status::ok();
50 }
51
52 LOG(INFO) << "Registered BLE advertiser with ID: " << advertiser_id;
53
54 String16 name_param;
55 bt_->GetName(&name_param);
56 std::string name(String8(name_param).string());
57
58 /* Advertising data: 16-bit Service UUID: Heart Rate Service, Tx power*/
59 std::vector<uint8_t> data{0x03, bluetooth::kEIRTypeComplete16BitUUIDs,
60 0x0D, 0x18,
61 0x02, bluetooth::kEIRTypeTxPower,
62 0x00};
63 data.push_back(name.length() + 1);
64 data.push_back(bluetooth::kEIRTypeCompleteLocalName);
65 data.insert(data.end(), name.c_str(), name.c_str() + name.length());
66
67 base::TimeDelta timeout;
68
69 bluetooth::AdvertiseSettings settings(
70 bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
71 bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, true);
72
73 bluetooth::AdvertiseData adv_data(data);
74 bluetooth::AdvertiseData scan_rsp;
75
76 android::sp<IBluetoothLeAdvertiser> ble;
77 bt_->GetLeAdvertiserInterface(&ble);
78 bool start_status;
79 ble->StartMultiAdvertising(advertiser_id, adv_data, scan_rsp, settings,
80 &start_status);
81 return Status::ok();
82 }
83
OnMultiAdvertiseCallback(int status,bool is_start,const android::bluetooth::AdvertiseSettings &)84 Status OnMultiAdvertiseCallback(
85 int status, bool is_start,
86 const android::bluetooth::AdvertiseSettings& /* settings */) {
87 LOG(INFO) << "Advertising" << (is_start ? " started" : " stopped");
88 return Status::ok();
89 };
90
91 private:
92 android::sp<android::bluetooth::IBluetooth> bt_;
93 DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback);
94 };
95
HeartRateServer(android::sp<android::bluetooth::IBluetooth> bluetooth,scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,bool advertise)96 HeartRateServer::HeartRateServer(
97 android::sp<android::bluetooth::IBluetooth> bluetooth,
98 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
99 bool advertise)
100 : simulation_started_(false),
101 bluetooth_(bluetooth),
102 server_if_(-1),
103 hr_notification_count_(0),
104 energy_expended_(0),
105 advertise_(advertise),
106 main_task_runner_(main_task_runner),
107 weak_ptr_factory_(this) {
108 CHECK(bluetooth_.get());
109 }
110
~HeartRateServer()111 HeartRateServer::~HeartRateServer() {
112 std::lock_guard<std::mutex> lock(mutex_);
113 if (!gatt_.get() || server_if_ == -1) return;
114
115 if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) return;
116
117 // Manually unregister ourselves from the daemon. It's good practice to do
118 // this, even though the daemon will automatically unregister us if this
119 // process exits.
120 gatt_->UnregisterServer(server_if_);
121 }
122
Run(const RunCallback & callback)123 bool HeartRateServer::Run(const RunCallback& callback) {
124 std::lock_guard<std::mutex> lock(mutex_);
125
126 if (pending_run_cb_) {
127 LOG(ERROR) << "Already started";
128 return false;
129 }
130
131 // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
132 bluetooth_->GetGattServerInterface(&gatt_);
133 if (!gatt_.get()) {
134 LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
135 return false;
136 }
137
138 // Register this instance as a GATT server. If this call succeeds, we will
139 // asynchronously receive a server ID via the OnServerRegistered callback.
140 bool status;
141 gatt_->RegisterServer(this, &status);
142 if (!status) {
143 LOG(ERROR) << "Failed to register with the server interface";
144 return false;
145 }
146
147 pending_run_cb_ = callback;
148
149 return true;
150 }
151
ScheduleNextMeasurement()152 void HeartRateServer::ScheduleNextMeasurement() {
153 main_task_runner_->PostDelayedTask(
154 FROM_HERE, base::Bind(&HeartRateServer::SendHeartRateMeasurement,
155 weak_ptr_factory_.GetWeakPtr()),
156 base::TimeDelta::FromSeconds(1));
157 }
158
SendHeartRateMeasurement()159 void HeartRateServer::SendHeartRateMeasurement() {
160 std::lock_guard<std::mutex> lock(mutex_);
161
162 // Send a notification or indication to all enabled devices.
163 bool found = false;
164 for (const auto& iter : device_ccc_map_) {
165 uint8_t ccc_val = iter.second;
166
167 if (!ccc_val) continue;
168
169 found = true;
170
171 // Don't send a notification if one is already pending for this device.
172 if (pending_notification_map_[iter.first]) continue;
173
174 std::vector<uint8_t> value;
175 BuildHeartRateMeasurementValue(&value);
176
177 bool status;
178 gatt_->SendNotification(server_if_, String16(String8(iter.first.c_str())),
179 hr_measurement_handle_, false, value, &status);
180 if (status) pending_notification_map_[iter.first] = true;
181 }
182
183 // Still enabled!
184 if (found) {
185 ScheduleNextMeasurement();
186 return;
187 }
188
189 // All clients disabled notifications.
190 simulation_started_ = false;
191
192 // TODO(armansito): We should keep track of closed connections here so that we
193 // don't send notifications to uninterested clients.
194 }
195
BuildHeartRateMeasurementValue(std::vector<uint8_t> * out_value)196 void HeartRateServer::BuildHeartRateMeasurementValue(
197 std::vector<uint8_t>* out_value) {
198 CHECK(out_value); // Assert that |out_value| is not nullptr.
199
200 // Default flags field. Here is what we put in there:
201 // Bit 0: 0 - 8-bit Heart Rate value
202 // Bits 1 & 2: 11 - Sensor contact feature supported and contact detected.
203 uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected;
204
205 // Our demo's heart rate. Pick a value between 90 and 130.
206 uint8_t heart_rate = base::RandInt(90, 130);
207
208 // On every tenth beat we include the Energy Expended value.
209 bool include_ee = false;
210 if (!(hr_notification_count_ % 10)) {
211 include_ee = true;
212 flags |= kHREnergyExpendedPresent;
213 }
214
215 hr_notification_count_++;
216 energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1);
217
218 // Add all the value bytes.
219 out_value->push_back(flags);
220 out_value->push_back(heart_rate);
221 if (include_ee) {
222 out_value->push_back(energy_expended_);
223 out_value->push_back(energy_expended_ >> 8);
224 }
225 }
226
OnServerRegistered(int status,int server_if)227 Status HeartRateServer::OnServerRegistered(int status, int server_if) {
228 std::lock_guard<std::mutex> lock(mutex_);
229
230 if (status != bluetooth::BLE_STATUS_SUCCESS) {
231 LOG(ERROR) << "Failed to register GATT server";
232 pending_run_cb_(false);
233 return Status::ok();
234 }
235
236 // Registration succeeded. Store our ID, as we need it for GATT server
237 // operations.
238 server_if_ = server_if;
239
240 LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
241
242 bluetooth::Service hrService(
243 0, true, kHRServiceUUID,
244 {{0,
245 kHRMeasurementUUID,
246 bluetooth::kCharacteristicPropertyNotify,
247 0,
248 {{0, kCCCDescriptorUUID, (bluetooth::kAttributePermissionRead |
249 bluetooth::kAttributePermissionWrite)}}},
250 {0,
251 kBodySensorLocationUUID,
252 bluetooth::kCharacteristicPropertyRead,
253 bluetooth::kAttributePermissionRead,
254 {}},
255 {0,
256 kHRControlPointUUID,
257 bluetooth::kCharacteristicPropertyWrite,
258 bluetooth::kAttributePermissionWrite,
259 {}}},
260 {});
261
262 bool op_status = true;
263
264 Status stat = gatt_->AddService(server_if_, (BluetoothGattService)hrService,
265 &op_status);
266 if (!stat.isOk()) {
267 LOG(ERROR) << "Failed to add service, status is: " /*<< stat*/;
268 pending_run_cb_(false);
269 return Status::ok();
270 }
271
272 if (!op_status) {
273 LOG(ERROR) << "Failed to add service";
274 pending_run_cb_(false);
275 return Status::ok();
276 }
277
278 LOG(INFO) << "Initiated AddService request";
279 return Status::ok();
280 }
281
OnServiceAdded(int status,const android::bluetooth::BluetoothGattService & service)282 Status HeartRateServer::OnServiceAdded(
283 int status, const android::bluetooth::BluetoothGattService& service) {
284 std::lock_guard<std::mutex> lock(mutex_);
285
286 if (status != bluetooth::BLE_STATUS_SUCCESS) {
287 LOG(ERROR) << "Failed to add Heart Rate service";
288 pending_run_cb_(false);
289 return Status::ok();
290 }
291
292 hr_service_handle_ = service.handle();
293 hr_measurement_handle_ = service.characteristics()[0].handle();
294 hr_measurement_cccd_handle_ =
295 service.characteristics()[0].descriptors()[0].handle();
296 body_sensor_loc_handle_ = service.characteristics()[1].handle();
297 hr_control_point_handle_ = service.characteristics()[2].handle();
298
299 LOG(INFO) << "Heart Rate service added";
300 pending_run_cb_(true);
301
302 if (advertise_) {
303 android::sp<IBluetoothLeAdvertiser> ble;
304 bluetooth_->GetLeAdvertiserInterface(&ble);
305 bool status;
306 ble->RegisterAdvertiser(new CLIBluetoothLeAdvertiserCallback(bluetooth_),
307 &status);
308 }
309
310 return Status::ok();
311 }
312
OnCharacteristicReadRequest(const String16 & device_address,int request_id,int offset,bool,int handle)313 Status HeartRateServer::OnCharacteristicReadRequest(
314 const String16& device_address, int request_id, int offset,
315 bool /* is_long */, int handle) {
316 std::lock_guard<std::mutex> lock(mutex_);
317
318 // This is where we handle an incoming characteristic read. Only the body
319 // sensor location characteristic is readable.
320 CHECK(handle == body_sensor_loc_handle_);
321
322 std::vector<uint8_t> value;
323 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
324 if (offset > 1)
325 error = bluetooth::GATT_ERROR_INVALID_OFFSET;
326 else if (offset == 0)
327 value.push_back(kHRBodyLocationFoot);
328
329 bool status;
330 gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
331 value, &status);
332 return Status::ok();
333 }
334
OnDescriptorReadRequest(const String16 & device_address,int request_id,int offset,bool,int handle)335 Status HeartRateServer::OnDescriptorReadRequest(const String16& device_address,
336 int request_id, int offset,
337 bool /* is_long */,
338 int handle) {
339 std::lock_guard<std::mutex> lock(mutex_);
340
341 // This is where we handle an incoming characteristic descriptor read. There
342 // is only one descriptor.
343 if (handle != hr_measurement_cccd_handle_) {
344 std::vector<uint8_t> value;
345 bool status;
346 gatt_->SendResponse(server_if_, device_address, request_id,
347 bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, offset,
348 value, &status);
349 return Status::ok();
350 }
351
352 // 16-bit value encoded as little-endian.
353 const uint8_t value_bytes[] = {
354 device_ccc_map_[std::string(String8(device_address).string())], 0x00};
355
356 std::vector<uint8_t> value;
357 bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
358 if (offset > 2)
359 error = bluetooth::GATT_ERROR_INVALID_OFFSET;
360 else
361 value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset);
362
363 bool status;
364 gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
365 value, &status);
366 return Status::ok();
367 }
368
OnCharacteristicWriteRequest(const String16 & device_address,int request_id,int offset,bool is_prepare_write,bool need_response,const std::vector<uint8_t> & value,int handle)369 Status HeartRateServer::OnCharacteristicWriteRequest(
370 const String16& device_address, int request_id, int offset,
371 bool is_prepare_write, bool need_response,
372 const std::vector<uint8_t>& value, int handle) {
373 std::lock_guard<std::mutex> lock(mutex_);
374
375 std::vector<uint8_t> dummy;
376
377 // This is where we handle an incoming characteristic write. The Heart Rate
378 // service doesn't really support prepared writes, so we just reject them to
379 // keep things simple.
380 if (is_prepare_write) {
381 bool status;
382 gatt_->SendResponse(server_if_, device_address, request_id,
383 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
384 dummy, &status);
385 return Status::ok();
386 }
387
388 // Heart Rate Control point is the only writable characteristic.
389 CHECK(handle == hr_control_point_handle_);
390
391 // Writes to the Heart Rate Control Point characteristic must contain a single
392 // byte with the value 0x01.
393 if (value.size() != 1 || value[0] != 0x01) {
394 bool status;
395 gatt_->SendResponse(server_if_, device_address, request_id,
396 bluetooth::GATT_ERROR_OUT_OF_RANGE, offset, dummy,
397 &status);
398 return Status::ok();
399 }
400
401 LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
402 energy_expended_ = 0;
403
404 if (!need_response) return Status::ok();
405
406 bool status;
407 gatt_->SendResponse(server_if_, device_address, request_id,
408 bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
409 return Status::ok();
410 }
411
OnDescriptorWriteRequest(const String16 & device_address,int request_id,int offset,bool is_prepare_write,bool need_response,const std::vector<uint8_t> & value,int handle)412 Status HeartRateServer::OnDescriptorWriteRequest(
413 const String16& device_address, int request_id, int offset,
414 bool is_prepare_write, bool need_response,
415 const std::vector<uint8_t>& value, int handle) {
416 std::lock_guard<std::mutex> lock(mutex_);
417
418 std::vector<uint8_t> dummy;
419
420 // This is where we handle an incoming characteristic write. The Heart Rate
421 // service doesn't really support prepared writes, so we just reject them to
422 // keep things simple.
423 if (is_prepare_write) {
424 bool status;
425 gatt_->SendResponse(server_if_, device_address, request_id,
426 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
427 dummy, &status);
428 return Status::ok();
429 }
430
431 // CCC is the only descriptor we have.
432 CHECK(handle == hr_measurement_cccd_handle_);
433
434 // CCC must contain 2 bytes for a 16-bit value in little-endian. The only
435 // allowed values here are 0x0000 and 0x0001.
436 if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) {
437 bool status;
438 gatt_->SendResponse(server_if_, device_address, request_id,
439 bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED,
440 offset, dummy, &status);
441 return Status::ok();
442 }
443
444 device_ccc_map_[std::string(String8(device_address).string())] = value[0];
445
446 LOG(INFO) << "Heart Rate Measurement CCC written - device: " << device_address
447 << " value: " << (int)value[0];
448
449 // Start the simulation.
450 if (!simulation_started_ && value[0]) {
451 simulation_started_ = true;
452 ScheduleNextMeasurement();
453 }
454
455 if (!need_response) return Status::ok();
456
457 bool status;
458 gatt_->SendResponse(server_if_, device_address, request_id,
459 bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
460 return Status::ok();
461 }
462
OnExecuteWriteRequest(const String16 & device_address,int request_id,bool)463 Status HeartRateServer::OnExecuteWriteRequest(const String16& device_address,
464 int request_id,
465 bool /* is_execute */) {
466 // We don't support Prepared Writes so, simply return Not Supported error.
467 std::vector<uint8_t> dummy;
468 bool status;
469 gatt_->SendResponse(server_if_, device_address, request_id,
470 bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy,
471 &status);
472
473 return Status::ok();
474 }
475
OnNotificationSent(const String16 & device_address,int status)476 Status HeartRateServer::OnNotificationSent(const String16& device_address,
477 int status) {
478 LOG(INFO) << "Notification was sent - device: " << device_address
479 << " status: " << status;
480 std::lock_guard<std::mutex> lock(mutex_);
481 pending_notification_map_[std::string(String8(device_address).string())] =
482 false;
483
484 return Status::ok();
485 }
486
OnConnectionStateChanged(const String16 & device_address,bool connected)487 Status HeartRateServer::OnConnectionStateChanged(const String16& device_address,
488 bool connected) {
489 LOG(INFO) << "Connection state changed - device: " << device_address
490 << " connected: " << (connected ? "true" : "false");
491 return Status::ok();
492 }
493 } // namespace heart_rate
494