• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 HIMSA II K/S - www.himsa.com.
3  * Represented by EHIMA - www.ehima.com
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <base/bind.h>
19 #include <base/callback.h>
20 #include <base/logging.h>
21 #include <base/strings/string_number_conversions.h>
22 #include <hardware/bt_gatt_types.h>
23 #include <hardware/bt_has.h>
24 
25 #include <list>
26 #include <map>
27 #include <string>
28 #include <vector>
29 
30 #include "bta_csis_api.h"
31 #include "bta_gatt_api.h"
32 #include "bta_gatt_queue.h"
33 #include "bta_groups.h"
34 #include "bta_has_api.h"
35 #include "bta_le_audio_uuids.h"
36 #include "btm_int.h"
37 #include "btm_sec.h"
38 #include "device/include/controller.h"
39 #include "gap_api.h"
40 #include "gatt_api.h"
41 #include "has_types.h"
42 #include "osi/include/log.h"
43 #include "osi/include/osi.h"
44 #include "osi/include/properties.h"
45 
46 using base::Closure;
47 using bluetooth::Uuid;
48 using bluetooth::csis::CsisClient;
49 using bluetooth::has::ConnectionState;
50 using bluetooth::has::ErrorCode;
51 using bluetooth::has::kFeatureBitPresetSynchronizationSupported;
52 using bluetooth::has::kHasPresetIndexInvalid;
53 using bluetooth::has::PresetInfo;
54 using bluetooth::has::PresetInfoReason;
55 using le_audio::has::HasClient;
56 using le_audio::has::HasCtpGroupOpCoordinator;
57 using le_audio::has::HasCtpNtf;
58 using le_audio::has::HasCtpOp;
59 using le_audio::has::HasDevice;
60 using le_audio::has::HasGattOpContext;
61 using le_audio::has::HasJournalRecord;
62 using le_audio::has::HasPreset;
63 using le_audio::has::kControlPointMandatoryOpcodesBitmask;
64 using le_audio::has::kControlPointSynchronizedOpcodesBitmask;
65 using le_audio::has::kUuidActivePresetIndex;
66 using le_audio::has::kUuidHearingAccessService;
67 using le_audio::has::kUuidHearingAidFeatures;
68 using le_audio::has::kUuidHearingAidPresetControlPoint;
69 using le_audio::has::PresetCtpChangeId;
70 using le_audio::has::PresetCtpOpcode;
71 
72 void btif_storage_add_leaudio_has_device(const RawAddress& address,
73                                          std::vector<uint8_t> presets_bin,
74                                          uint8_t features,
75                                          uint8_t active_preset);
76 bool btif_storage_get_leaudio_has_presets(const RawAddress& address,
77                                           std::vector<uint8_t>& presets_bin,
78                                           uint8_t& active_preset);
79 void btif_storage_set_leaudio_has_presets(const RawAddress& address,
80                                           std::vector<uint8_t> presets_bin);
81 bool btif_storage_get_leaudio_has_features(const RawAddress& address,
82                                            uint8_t& features);
83 void btif_storage_set_leaudio_has_features(const RawAddress& address,
84                                            uint8_t features);
85 void btif_storage_set_leaudio_has_active_preset(const RawAddress& address,
86                                                 uint8_t active_preset);
87 void btif_storage_remove_leaudio_has(const RawAddress& address);
88 
89 extern bool gatt_profile_get_eatt_support(const RawAddress& remote_bda);
90 
91 namespace {
92 class HasClientImpl;
93 HasClientImpl* instance;
94 
95 /**
96  * -----------------------------------------------------------------------------
97  * Hearing Access Service - Client role
98  * -----------------------------------------------------------------------------
99  * Overview:
100  *
101  * This is Hearing Access Service client class.
102  *
103  * Each connected peer device supporting Hearing Access Service (HAS) is being
104  * connected and has its characteristics discovered. All the characteristics
105  * and descriptors (incl. the optional ones) are being read or written during
106  * this initial connection stage. Encryption is also verified. If all of this
107  * succeeds the appropriate callbacks are being called to notify upper layer
108  * about the successful HAS device connection and its features and the list
109  * of available audio configuration presets.
110  *
111  * Each HA device is expected to have the HAS service instantiated. It must
112  * contain Hearing Aid Features characteristic and optionally Presets Control
113  * Point and Active Preset Index characteristics, allowing the user to read
114  * preset details, switch currently active preset and possibly rename some of
115  * them.
116  *
117  * Hearing Aid Features characteristic informs the client about the type of
118  * Hearign Aids device (Monaural, Binaural or Banded), which operations are
119  * supported via the Preset Control Point characteristic, about dynamically
120  * changing list of available presets, writable presets and the support for
121  * synchronised preset change operations on the Binaural Hearing Aid devices.
122  */
123 class HasClientImpl : public HasClient {
124  public:
HasClientImpl(bluetooth::has::HasClientCallbacks * callbacks,base::Closure initCb)125   HasClientImpl(bluetooth::has::HasClientCallbacks* callbacks,
126                 base::Closure initCb)
127       : gatt_if_(0), callbacks_(callbacks) {
128     BTA_GATTC_AppRegister(
129         [](tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
130           if (instance && p_data) instance->GattcCallback(event, p_data);
131         },
132         base::Bind(
133             [](base::Closure initCb, uint8_t client_id, uint8_t status) {
134               if (status != GATT_SUCCESS) {
135                 LOG(ERROR) << "Can't start Hearing Aid Service client "
136                               "profile - no gatt clients left!";
137                 return;
138               }
139               instance->gatt_if_ = client_id;
140               initCb.Run();
141             },
142             initCb),
143         true);
144   }
145 
146   ~HasClientImpl() override = default;
147 
Connect(const RawAddress & address)148   void Connect(const RawAddress& address) override {
149     DLOG(INFO) << __func__ << ": " << address;
150 
151     std::vector<RawAddress> addresses = {address};
152     auto csis_api = CsisClient::Get();
153     if (csis_api != nullptr) {
154       // Connect entire CAS set of devices
155       auto group_id = csis_api->GetGroupId(
156           address, bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE));
157       addresses = csis_api->GetDeviceList(group_id);
158     }
159 
160     if (addresses.empty()) {
161       LOG(WARNING) << __func__ << ": " << address << " is not part of any set";
162       addresses = {address};
163     }
164 
165     for (auto const& addr : addresses) {
166       auto device = std::find_if(devices_.begin(), devices_.end(),
167                                  HasDevice::MatchAddress(addr));
168       if (device == devices_.end()) {
169         devices_.emplace_back(addr, true);
170         BTA_GATTC_Open(gatt_if_, addr, BTM_BLE_DIRECT_CONNECTION, false);
171 
172       } else {
173         device->is_connecting_actively = true;
174         if (!device->IsConnected())
175           BTA_GATTC_Open(gatt_if_, addr, BTM_BLE_DIRECT_CONNECTION, false);
176       }
177     }
178   }
179 
AddFromStorage(const RawAddress & address,uint8_t features,uint16_t is_acceptlisted)180   void AddFromStorage(const RawAddress& address, uint8_t features,
181                       uint16_t is_acceptlisted) {
182     DLOG(INFO) << __func__ << ": " << address
183                << ", features=" << loghex(features)
184                << ", isAcceptlisted=" << is_acceptlisted;
185 
186     /* Notify upper layer about the device */
187     callbacks_->OnDeviceAvailable(address, features);
188     if (is_acceptlisted) {
189       auto device = std::find_if(devices_.begin(), devices_.end(),
190                                  HasDevice::MatchAddress(address));
191       if (device == devices_.end())
192         devices_.push_back(HasDevice(address, features));
193 
194       /* Connect in background */
195       BTA_GATTC_Open(gatt_if_, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false);
196     }
197   }
198 
Disconnect(const RawAddress & address)199   void Disconnect(const RawAddress& address) override {
200     DLOG(INFO) << __func__ << ": " << address;
201 
202     std::vector<RawAddress> addresses = {address};
203     auto csis_api = CsisClient::Get();
204     if (csis_api != nullptr) {
205       // Disconnect entire CAS set of devices
206       auto group_id = csis_api->GetGroupId(
207           address, bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE));
208       addresses = csis_api->GetDeviceList(group_id);
209     }
210 
211     if (addresses.empty()) {
212       LOG(WARNING) << __func__ << ": " << address << " is not part of any set";
213       addresses = {address};
214     }
215 
216     for (auto const& addr : addresses) {
217       auto device = std::find_if(devices_.begin(), devices_.end(),
218                                  HasDevice::MatchAddress(addr));
219       if (device == devices_.end()) {
220         LOG(WARNING) << "Device not connected to profile" << addr;
221         return;
222       }
223 
224       auto conn_id = device->conn_id;
225       auto is_connecting_actively = device->is_connecting_actively;
226       devices_.erase(device);
227 
228       if (conn_id != GATT_INVALID_CONN_ID) {
229         BTA_GATTC_Close(conn_id);
230         callbacks_->OnConnectionState(ConnectionState::DISCONNECTED, addr);
231       } else {
232         /* Removes active connection. */
233         if (is_connecting_actively) BTA_GATTC_CancelOpen(gatt_if_, addr, true);
234       }
235 
236       /* Removes all registrations for connection. */
237       BTA_GATTC_CancelOpen(0, addr, false);
238     }
239   }
240 
UpdateJournalOpEntryStatus(HasDevice & device,HasGattOpContext context,tGATT_STATUS status)241   void UpdateJournalOpEntryStatus(HasDevice& device, HasGattOpContext context,
242                                   tGATT_STATUS status) {
243     /* Find journal entry by the context and update */
244     auto journal_entry = std::find_if(
245         device.has_journal_.begin(), device.has_journal_.end(),
246         [&context](auto const& record) {
247           if (record.is_operation) {
248             return HasGattOpContext(record.op_context_handle) == context;
249           }
250           return false;
251         });
252 
253     if (journal_entry == device.has_journal_.end()) {
254       LOG(WARNING) << "Journaling error or journal length limit was set to "
255                       "low. Unable to log the operation outcome.";
256       return;
257     }
258 
259     if (journal_entry == device.has_journal_.end()) {
260       LOG(ERROR) << __func__
261                  << " Unable to find operation context in the journal!";
262       return;
263     }
264 
265     journal_entry->op_status = status;
266   }
267 
ExtractPendingCtpOp(uint16_t op_id)268   std::optional<HasCtpOp> ExtractPendingCtpOp(uint16_t op_id) {
269     auto op_it =
270         std::find_if(pending_operations_.begin(), pending_operations_.end(),
271                      [op_id](auto const& el) { return op_id == el.op_id; });
272 
273     if (op_it != pending_operations_.end()) {
274       auto op = *op_it;
275       pending_operations_.erase(op_it);
276 
277       return op;
278     }
279     return std::nullopt;
280   }
281 
EnqueueCtpOp(HasCtpOp op)282   void EnqueueCtpOp(HasCtpOp op) { pending_operations_.push_back(op); }
283 
OnHasActivePresetCycleStatus(uint16_t conn_id,tGATT_STATUS status,void * user_data)284   void OnHasActivePresetCycleStatus(uint16_t conn_id, tGATT_STATUS status,
285                                     void* user_data) {
286     DLOG(INFO) << __func__ << " status: " << +status;
287 
288     auto device = GetDevice(conn_id);
289     if (!device) {
290       LOG(WARNING) << "Device not connected to profile, conn_id=" << +conn_id;
291       return;
292     }
293 
294     /* Journal update */
295     LOG_ASSERT(user_data != nullptr) << "Has operation context is missing!";
296     auto context = HasGattOpContext(user_data);
297     UpdateJournalOpEntryStatus(*device, context, status);
298 
299     auto op_opt = ExtractPendingCtpOp(context.ctp_op_id);
300     if (status == GATT_SUCCESS) return;
301 
302     /* This could be one of the coordinated group preset change request */
303     pending_group_operation_timeouts_.erase(context.ctp_op_id);
304 
305     /* Error handling */
306     if (!op_opt.has_value()) {
307       LOG(ERROR) << __func__ << " Unknown operation error";
308       return;
309     }
310     auto op = op_opt.value();
311     callbacks_->OnActivePresetSelectError(op.addr_or_group,
312                                           GattStatus2SvcErrorCode(status));
313 
314     if (status == GATT_DATABASE_OUT_OF_SYNC) {
315       LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
316       ClearDeviceInformationAndStartSearch(device);
317     }
318   }
319 
OnHasPresetNameSetStatus(uint16_t conn_id,tGATT_STATUS status,void * user_data)320   void OnHasPresetNameSetStatus(uint16_t conn_id, tGATT_STATUS status,
321                                 void* user_data) {
322     auto device = GetDevice(conn_id);
323     if (!device) {
324       LOG(WARNING) << "Device not connected to profile, conn_id=" << +conn_id;
325       return;
326     }
327 
328     LOG_ASSERT(user_data != nullptr) << "Has operation context is missing!";
329     HasGattOpContext context(user_data);
330 
331     /* Journal update */
332     UpdateJournalOpEntryStatus(*device, context, status);
333 
334     auto op_opt = ExtractPendingCtpOp(context.ctp_op_id);
335     if (status == GATT_SUCCESS) return;
336 
337     /* This could be one of the coordinated group preset change request */
338     pending_group_operation_timeouts_.erase(context.ctp_op_id);
339 
340     /* Error handling */
341     if (!op_opt.has_value()) {
342       LOG(ERROR) << __func__ << " Unknown operation error";
343       return;
344     }
345     auto op = op_opt.value();
346     callbacks_->OnSetPresetNameError(device->addr, op.index,
347                                      GattStatus2SvcErrorCode(status));
348     if (status == GATT_DATABASE_OUT_OF_SYNC) {
349       LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
350       ClearDeviceInformationAndStartSearch(device);
351     }
352   }
353 
OnHasPresetNameGetStatus(uint16_t conn_id,tGATT_STATUS status,void * user_data)354   void OnHasPresetNameGetStatus(uint16_t conn_id, tGATT_STATUS status,
355                                 void* user_data) {
356     auto device = GetDevice(conn_id);
357     if (!device) {
358       LOG(WARNING) << "Device not connected to profile, conn_id=" << +conn_id;
359       return;
360     }
361 
362     LOG_ASSERT(user_data != nullptr) << "Has operation context is missing!";
363     HasGattOpContext context(user_data);
364 
365     /* Journal update */
366     UpdateJournalOpEntryStatus(*device, context, status);
367 
368     auto op_opt = ExtractPendingCtpOp(context.ctp_op_id);
369     if (status == GATT_SUCCESS) return;
370 
371     /* Error handling */
372     if (!op_opt.has_value()) {
373       LOG(ERROR) << __func__ << " Unknown operation error";
374       return;
375     }
376     auto op = op_opt.value();
377     callbacks_->OnPresetInfoError(device->addr, op.index,
378                                   GattStatus2SvcErrorCode(status));
379 
380     if (status == GATT_DATABASE_OUT_OF_SYNC) {
381       LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
382       ClearDeviceInformationAndStartSearch(device);
383     } else {
384       LOG_ERROR("Devices %s: Control point not usable. Disconnecting!",
385                 device->addr.ToString().c_str());
386       BTA_GATTC_Close(device->conn_id);
387     }
388   }
389 
OnHasPresetIndexOperation(uint16_t conn_id,tGATT_STATUS status,void * user_data)390   void OnHasPresetIndexOperation(uint16_t conn_id, tGATT_STATUS status,
391                                  void* user_data) {
392     DLOG(INFO) << __func__;
393 
394     auto device = GetDevice(conn_id);
395     if (!device) {
396       LOG(WARNING) << "Device not connected to profile, conn_id=" << +conn_id;
397       return;
398     }
399 
400     LOG_ASSERT(user_data != nullptr) << "Has operation context is missing!";
401     HasGattOpContext context(user_data);
402 
403     /* Journal update */
404     UpdateJournalOpEntryStatus(*device, context, status);
405 
406     auto op_opt = ExtractPendingCtpOp(context.ctp_op_id);
407     if (status == GATT_SUCCESS) return;
408 
409     /* This could be one of the coordinated group preset change request */
410     pending_group_operation_timeouts_.erase(context.ctp_op_id);
411 
412     /* Error handling */
413     if (!op_opt.has_value()) {
414       LOG(ERROR) << __func__ << " Unknown operation error";
415       return;
416     }
417 
418     auto op = op_opt.value();
419     if (op.opcode == PresetCtpOpcode::READ_PRESETS) {
420       callbacks_->OnPresetInfoError(device->addr, op.index,
421                                     GattStatus2SvcErrorCode(status));
422 
423     } else {
424       callbacks_->OnActivePresetSelectError(op.addr_or_group,
425                                             GattStatus2SvcErrorCode(status));
426     }
427 
428     if (status == GATT_DATABASE_OUT_OF_SYNC) {
429       LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
430       ClearDeviceInformationAndStartSearch(device);
431     } else {
432       LOG_ERROR("Devices %s: Control point not usable. Disconnecting!",
433                 device->addr.ToString().c_str());
434       BTA_GATTC_Close(device->conn_id);
435     }
436   }
437 
CpReadAllPresetsOperation(HasCtpOp operation)438   void CpReadAllPresetsOperation(HasCtpOp operation) {
439     DLOG(INFO) << __func__ << " Operation: " << operation;
440 
441     if (std::holds_alternative<int>(operation.addr_or_group)) {
442       LOG(ERROR) << __func__
443                  << " Read all presets on the entire group not supported.";
444       callbacks_->OnPresetInfoError(operation.addr_or_group, operation.index,
445                                     ErrorCode::OPERATION_NOT_POSSIBLE);
446       return;
447     }
448 
449     auto device = std::find_if(
450         devices_.begin(), devices_.end(),
451         HasDevice::MatchAddress(std::get<RawAddress>(operation.addr_or_group)));
452     if (device == devices_.end()) {
453       LOG(WARNING) << __func__ << " Device not connected to profile addr: "
454                    << std::get<RawAddress>(operation.addr_or_group);
455       callbacks_->OnPresetInfoError(device->addr, operation.index,
456                                     ErrorCode::OPERATION_NOT_POSSIBLE);
457       return;
458     }
459 
460     if (!device->SupportsPresets()) {
461       callbacks_->OnPresetInfoError(device->addr, operation.index,
462                                     ErrorCode::OPERATION_NOT_SUPPORTED);
463     }
464 
465     auto context = HasGattOpContext(operation);
466 
467     /* Journal update */
468     device->has_journal_.Append(HasJournalRecord(operation, context));
469 
470     /* Write to control point */
471     EnqueueCtpOp(operation);
472     BtaGattQueue::WriteCharacteristic(
473         device->conn_id, device->cp_handle, operation.ToCharacteristicValue(),
474         GATT_WRITE,
475         [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
476            const uint8_t* value, void* user_data) {
477           if (instance)
478             instance->OnHasPresetNameGetStatus(conn_id, status, user_data);
479         },
480         context);
481   }
482 
CpPresetIndexOperationWriteReq(HasDevice & device,HasCtpOp & operation)483   ErrorCode CpPresetIndexOperationWriteReq(HasDevice& device,
484                                            HasCtpOp& operation) {
485     DLOG(INFO) << __func__ << " Operation: " << operation;
486 
487     if (!device.IsConnected()) return ErrorCode::OPERATION_NOT_POSSIBLE;
488 
489     if (!device.SupportsPresets()) return ErrorCode::OPERATION_NOT_SUPPORTED;
490 
491     if (!device.SupportsOperation(operation.opcode))
492       return operation.IsGroupRequest()
493                  ? ErrorCode::GROUP_OPERATION_NOT_SUPPORTED
494                  : ErrorCode::OPERATION_NOT_SUPPORTED;
495 
496     if (!device.IsValidPreset(operation.index))
497       return ErrorCode::INVALID_PRESET_INDEX;
498 
499     auto context = HasGattOpContext(operation);
500 
501     /* Journal update */
502     device.has_journal_.Append(HasJournalRecord(operation, context));
503 
504     /* Write to control point */
505     EnqueueCtpOp(operation);
506     BtaGattQueue::WriteCharacteristic(
507         device.conn_id, device.cp_handle, operation.ToCharacteristicValue(),
508         GATT_WRITE,
509         [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
510            const uint8_t* value, void* user_data) {
511           if (instance)
512             instance->OnHasPresetIndexOperation(conn_id, status, user_data);
513         },
514         context);
515 
516     return ErrorCode::NO_ERROR;
517   }
518 
AreAllDevicesAvailable(const std::vector<RawAddress> & addresses)519   bool AreAllDevicesAvailable(const std::vector<RawAddress>& addresses) {
520     for (auto& addr : addresses) {
521       auto device = std::find_if(devices_.begin(), devices_.end(),
522                                  HasDevice::MatchAddress(addr));
523       if (device == devices_.end() || !device->IsConnected()) {
524         return false;
525       }
526     }
527     return true;
528   }
529 
CpPresetOperationCaller(HasCtpOp operation,std::function<ErrorCode (HasDevice & device,HasCtpOp & operation)> write_cb)530   ErrorCode CpPresetOperationCaller(
531       HasCtpOp operation,
532       std::function<ErrorCode(HasDevice& device, HasCtpOp& operation)>
533           write_cb) {
534     DLOG(INFO) << __func__ << " Operation: " << operation;
535     auto status = ErrorCode::NO_ERROR;
536 
537     if (operation.IsGroupRequest()) {
538       auto csis_api = CsisClient::Get();
539       if (csis_api == nullptr) {
540         /* No CSIS means no group operations */
541         status = ErrorCode::GROUP_OPERATION_NOT_SUPPORTED;
542 
543       } else {
544         auto group_id = operation.GetGroupId();
545         auto addresses = csis_api->GetDeviceList(group_id);
546 
547         /* Perform the operation only when all the devices are available */
548         if (!AreAllDevicesAvailable(addresses)) {
549           addresses.clear();
550         }
551 
552         if (addresses.empty()) {
553           status = ErrorCode::OPERATION_NOT_POSSIBLE;
554 
555         } else {
556           /* Make this a coordinated operation */
557           pending_group_operation_timeouts_.emplace(
558               operation.op_id, HasCtpGroupOpCoordinator(addresses, operation));
559 
560           if (operation.IsSyncedOperation()) {
561             status = ErrorCode::GROUP_OPERATION_NOT_SUPPORTED;
562 
563             /* Clear the error if we find device to forward the operation */
564             bool was_sent = false;
565             for (auto& addr : addresses) {
566               auto device = std::find_if(devices_.begin(), devices_.end(),
567                                          HasDevice::MatchAddress(addr));
568               if (device != devices_.end()) {
569                 status = write_cb(*device, operation);
570                 if (status == ErrorCode::NO_ERROR) {
571                   was_sent = true;
572                   break;
573                 }
574               }
575             }
576             if (!was_sent) status = ErrorCode::OPERATION_NOT_POSSIBLE;
577 
578           } else {
579             status = ErrorCode::GROUP_OPERATION_NOT_SUPPORTED;
580 
581             for (auto& addr : addresses) {
582               auto device = std::find_if(devices_.begin(), devices_.end(),
583                                          HasDevice::MatchAddress(addr));
584               if (device != devices_.end()) {
585                 status = write_cb(*device, operation);
586                 if (status != ErrorCode::NO_ERROR) break;
587               }
588             }
589           }
590 
591           /* Erase group op coordinator on error */
592           if (status != ErrorCode::NO_ERROR) {
593             pending_group_operation_timeouts_.erase(operation.op_id);
594           }
595         }
596       }
597 
598     } else {
599       auto device = std::find_if(devices_.begin(), devices_.end(),
600                                  HasDevice::MatchAddress(std::get<RawAddress>(
601                                      operation.addr_or_group)));
602       status = ErrorCode::OPERATION_NOT_POSSIBLE;
603       if (device != devices_.end()) status = write_cb(*device, operation);
604     }
605 
606     return status;
607   }
608 
CpPresetIndexOperation(HasCtpOp operation)609   void CpPresetIndexOperation(HasCtpOp operation) {
610     LOG(INFO) << __func__ << " Operation: " << operation;
611 
612     auto status = CpPresetOperationCaller(
613         operation, [](HasDevice& device, HasCtpOp operation) -> ErrorCode {
614           if (instance)
615             return instance->CpPresetIndexOperationWriteReq(device, operation);
616           return ErrorCode::OPERATION_NOT_POSSIBLE;
617         });
618 
619     if (status != ErrorCode::NO_ERROR) {
620       switch (operation.opcode) {
621         case PresetCtpOpcode::READ_PRESETS:
622           LOG_ASSERT(
623               std::holds_alternative<RawAddress>(operation.addr_or_group))
624               << " Unsupported group operation!";
625 
626           callbacks_->OnPresetInfoError(
627               std::get<RawAddress>(operation.addr_or_group), operation.index,
628               status);
629           break;
630         case PresetCtpOpcode::SET_ACTIVE_PRESET:
631         case PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC:
632           callbacks_->OnActivePresetSelectError(operation.addr_or_group,
633                                                 status);
634           break;
635         default:
636           break;
637       }
638     }
639   }
640 
CpPresetsCycleOperationWriteReq(HasDevice & device,HasCtpOp & operation)641   ErrorCode CpPresetsCycleOperationWriteReq(HasDevice& device,
642                                             HasCtpOp& operation) {
643     DLOG(INFO) << __func__ << " addr: " << device.addr
644                << " operation: " << operation;
645 
646     if (!device.IsConnected()) return ErrorCode::OPERATION_NOT_POSSIBLE;
647 
648     if (!device.SupportsPresets()) return ErrorCode::OPERATION_NOT_SUPPORTED;
649 
650     if (!device.SupportsOperation(operation.opcode))
651       return operation.IsGroupRequest()
652                  ? ErrorCode::GROUP_OPERATION_NOT_SUPPORTED
653                  : ErrorCode::OPERATION_NOT_SUPPORTED;
654 
655     auto context = HasGattOpContext(operation);
656 
657     /* Journal update */
658     device.has_journal_.Append(HasJournalRecord(operation, context));
659 
660     /* Write to control point */
661     EnqueueCtpOp(operation);
662     BtaGattQueue::WriteCharacteristic(
663         device.conn_id, device.cp_handle, operation.ToCharacteristicValue(),
664         GATT_WRITE,
665         [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
666            const uint8_t* value, void* user_data) {
667           if (instance)
668             instance->OnHasActivePresetCycleStatus(conn_id, status, user_data);
669         },
670         context);
671     return ErrorCode::NO_ERROR;
672   }
673 
CpPresetsCycleOperation(HasCtpOp operation)674   void CpPresetsCycleOperation(HasCtpOp operation) {
675     DLOG(INFO) << __func__ << " Operation: " << operation;
676 
677     auto status = CpPresetOperationCaller(
678         operation, [](HasDevice& device, HasCtpOp operation) -> ErrorCode {
679           if (instance)
680             return instance->CpPresetsCycleOperationWriteReq(device, operation);
681           return ErrorCode::OPERATION_NOT_POSSIBLE;
682         });
683 
684     if (status != ErrorCode::NO_ERROR)
685       callbacks_->OnActivePresetSelectError(operation.addr_or_group, status);
686   }
687 
CpWritePresetNameOperationWriteReq(HasDevice & device,HasCtpOp operation)688   ErrorCode CpWritePresetNameOperationWriteReq(HasDevice& device,
689                                                HasCtpOp operation) {
690     DLOG(INFO) << __func__ << " addr: " << device.addr
691                << " operation: " << operation;
692 
693     if (!device.IsConnected()) return ErrorCode::OPERATION_NOT_POSSIBLE;
694 
695     if (!device.SupportsPresets()) return ErrorCode::OPERATION_NOT_SUPPORTED;
696 
697     if (!device.IsValidPreset(operation.index, true))
698       return device.IsValidPreset(operation.index)
699                  ? ErrorCode::SET_NAME_NOT_ALLOWED
700                  : ErrorCode::INVALID_PRESET_INDEX;
701 
702     if (!device.SupportsOperation(operation.opcode))
703       return ErrorCode::OPERATION_NOT_SUPPORTED;
704 
705     if (operation.name.value_or("").length() >
706         le_audio::has::HasPreset::kPresetNameLengthLimit)
707       return ErrorCode::INVALID_PRESET_NAME_LENGTH;
708 
709     auto context = HasGattOpContext(operation, operation.index);
710 
711     /* Journal update */
712     device.has_journal_.Append(HasJournalRecord(operation, context));
713 
714     /* Write to control point */
715     EnqueueCtpOp(operation);
716     BtaGattQueue::WriteCharacteristic(
717         device.conn_id, device.cp_handle, operation.ToCharacteristicValue(),
718         GATT_WRITE,
719         [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
720            const uint8_t* value, void* user_data) {
721           if (instance)
722             instance->OnHasPresetNameSetStatus(conn_id, status, user_data);
723         },
724         context);
725 
726     return ErrorCode::NO_ERROR;
727   }
728 
CpWritePresetNameOperation(HasCtpOp operation)729   void CpWritePresetNameOperation(HasCtpOp operation) {
730     DLOG(INFO) << __func__ << " operation: " << operation;
731 
732     auto status = ErrorCode::NO_ERROR;
733 
734     std::vector<RawAddress> addresses;
735     if (operation.IsGroupRequest()) {
736       auto csis_api = CsisClient::Get();
737       if (csis_api != nullptr) {
738         addresses = csis_api->GetDeviceList(operation.GetGroupId());
739 
740         /* Make this a coordinated operation */
741         pending_group_operation_timeouts_.emplace(
742             operation.op_id, HasCtpGroupOpCoordinator(addresses, operation));
743       }
744 
745     } else {
746       addresses = {operation.GetDeviceAddr()};
747     }
748 
749     status = ErrorCode::OPERATION_NOT_POSSIBLE;
750 
751     /* Perform the operation only when all the devices are available */
752     if (!AreAllDevicesAvailable(addresses)) {
753       addresses.clear();
754     }
755 
756     for (auto& addr : addresses) {
757       auto device = std::find_if(devices_.begin(), devices_.end(),
758                                  HasDevice::MatchAddress(addr));
759       if (device != devices_.end()) {
760         status = CpWritePresetNameOperationWriteReq(*device, operation);
761         if (status != ErrorCode::NO_ERROR) {
762           LOG(ERROR) << __func__
763                      << " Control point write error: " << (int)status;
764           break;
765         }
766       }
767     }
768 
769     if (status != ErrorCode::NO_ERROR) {
770       if (operation.IsGroupRequest())
771         pending_group_operation_timeouts_.erase(operation.op_id);
772 
773       callbacks_->OnSetPresetNameError(operation.addr_or_group, operation.index,
774                                        status);
775     }
776   }
777 
shouldRequestSyncedOp(std::variant<RawAddress,int> addr_or_group_id,PresetCtpOpcode opcode)778   bool shouldRequestSyncedOp(std::variant<RawAddress, int> addr_or_group_id,
779                              PresetCtpOpcode opcode) {
780     /* Do not select locally synced ops when not performing group operations,
781      * You never know if the user will make another call for the other devices
782      * in this set even though the may support locally synced operations.
783      */
784     if (std::holds_alternative<RawAddress>(addr_or_group_id)) return false;
785 
786     auto csis_api = CsisClient::Get();
787     if (csis_api == nullptr) return false;
788 
789     auto addresses = csis_api->GetDeviceList(std::get<int>(addr_or_group_id));
790     if (addresses.empty()) return false;
791 
792     for (auto& addr : addresses) {
793       auto device = std::find_if(devices_.begin(), devices_.end(),
794                                  HasDevice::MatchAddress(addr));
795       if (device != devices_.end()) {
796         if (device->SupportsOperation(opcode)) return true;
797       }
798     }
799 
800     return false;
801   }
802 
SelectActivePreset(std::variant<RawAddress,int> addr_or_group_id,uint8_t preset_index)803   void SelectActivePreset(std::variant<RawAddress, int> addr_or_group_id,
804                           uint8_t preset_index) override {
805     DLOG(INFO) << __func__;
806 
807     auto opcode = shouldRequestSyncedOp(addr_or_group_id,
808                                         PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC)
809                       ? PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC
810                       : PresetCtpOpcode::SET_ACTIVE_PRESET;
811 
812     CpPresetIndexOperation(HasCtpOp(addr_or_group_id, opcode, preset_index));
813   }
814 
NextActivePreset(std::variant<RawAddress,int> addr_or_group_id)815   void NextActivePreset(
816       std::variant<RawAddress, int> addr_or_group_id) override {
817     DLOG(INFO) << __func__;
818 
819     auto opcode = shouldRequestSyncedOp(addr_or_group_id,
820                                         PresetCtpOpcode::SET_NEXT_PRESET_SYNC)
821                       ? PresetCtpOpcode::SET_NEXT_PRESET_SYNC
822                       : PresetCtpOpcode::SET_NEXT_PRESET;
823 
824     CpPresetsCycleOperation(HasCtpOp(addr_or_group_id, opcode));
825   }
826 
PreviousActivePreset(std::variant<RawAddress,int> addr_or_group_id)827   void PreviousActivePreset(
828       std::variant<RawAddress, int> addr_or_group_id) override {
829     DLOG(INFO) << __func__;
830 
831     auto opcode = shouldRequestSyncedOp(addr_or_group_id,
832                                         PresetCtpOpcode::SET_PREV_PRESET_SYNC)
833                       ? PresetCtpOpcode::SET_PREV_PRESET_SYNC
834                       : PresetCtpOpcode::SET_PREV_PRESET;
835 
836     CpPresetsCycleOperation(HasCtpOp(addr_or_group_id, opcode));
837   }
838 
GetPresetInfo(const RawAddress & address,uint8_t preset_index)839   void GetPresetInfo(const RawAddress& address, uint8_t preset_index) override {
840     auto device = std::find_if(devices_.begin(), devices_.end(),
841                                HasDevice::MatchAddress(address));
842     if (device == devices_.end()) {
843       LOG(WARNING) << "Device not connected to profile" << address;
844       return;
845     }
846 
847     DLOG(INFO) << __func__ << " preset idx: " << +preset_index;
848 
849     /* Due to mandatory control point notifications or indications, preset
850      * details are always up to date. However we have to be able to do the
851      * READ_PRESET_BY_INDEX, to pass the test specification requirements.
852      */
853     if (osi_property_get_bool("persist.bluetooth.has.always_use_preset_cache",
854                               true)) {
855       auto* preset = device->GetPreset(preset_index);
856       if (preset == nullptr) {
857         LOG(ERROR) << __func__ << "Invalid preset request" << address;
858         callbacks_->OnPresetInfoError(address, preset_index,
859                                       ErrorCode::INVALID_PRESET_INDEX);
860         return;
861       }
862 
863       callbacks_->OnPresetInfo(address,
864                                PresetInfoReason::PRESET_INFO_REQUEST_RESPONSE,
865                                {{.preset_index = preset_index,
866                                  .writable = preset->IsWritable(),
867                                  .available = preset->IsAvailable(),
868                                  .preset_name = preset->GetName()}});
869     } else {
870       CpPresetIndexOperation(
871           HasCtpOp(address, PresetCtpOpcode::READ_PRESETS, preset_index));
872     }
873   }
874 
SetPresetName(std::variant<RawAddress,int> addr_or_group_id,uint8_t preset_index,std::string name)875   void SetPresetName(std::variant<RawAddress, int> addr_or_group_id,
876                      uint8_t preset_index, std::string name) override {
877     DLOG(INFO) << __func__ << "preset_idx: " << +preset_index
878                << ", name: " << name;
879 
880     CpWritePresetNameOperation(HasCtpOp(addr_or_group_id,
881                                         PresetCtpOpcode::WRITE_PRESET_NAME,
882                                         preset_index, 1 /* Don't care */, name));
883   }
884 
CleanUp()885   void CleanUp() {
886     BTA_GATTC_AppDeregister(gatt_if_);
887     for (auto& device : devices_) {
888       if (device.conn_id != GATT_INVALID_CONN_ID)
889         BTA_GATTC_Close(device.conn_id);
890       DoDisconnectCleanUp(device);
891     }
892 
893     devices_.clear();
894     pending_operations_.clear();
895   }
896 
Dump(int fd) const897   void Dump(int fd) const {
898     std::stringstream stream;
899     if (devices_.size()) {
900       stream << "  {\"Known HAS devices\": [";
901       for (const auto& device : devices_) {
902         stream << "\n    {";
903         device.Dump(stream);
904         stream << "\n    },\n";
905       }
906       stream << "  ]}\n\n";
907     } else {
908       stream << "  \"No known HAS devices\"\n\n";
909     }
910     dprintf(fd, "%s", stream.str().c_str());
911   }
912 
OnGroupOpCoordinatorTimeout(void * p)913   void OnGroupOpCoordinatorTimeout(void* p) {
914     LOG(ERROR) << __func__ << ": Coordinated operation timeout: "
915                << " not all the devices notified their state change on time.";
916 
917     /* Clear pending group operations */
918     pending_group_operation_timeouts_.clear();
919     HasCtpGroupOpCoordinator::Cleanup();
920   }
921 
922  private:
WriteAllNeededCcc(const HasDevice & device)923   void WriteAllNeededCcc(const HasDevice& device) {
924     if (device.conn_id == GATT_INVALID_CONN_ID) {
925       LOG_ERROR("Device %s is not connected", device.addr.ToString().c_str());
926       return;
927     }
928 
929     /* Write CCC values even remote should have it */
930     LOG_INFO("Subscribing for notification/indications");
931     if (device.SupportsFeaturesNotification()) {
932       SubscribeForNotifications(device.conn_id, device.addr,
933                                 device.features_handle,
934                                 device.features_ccc_handle);
935     }
936 
937     if (device.SupportsPresets()) {
938       SubscribeForNotifications(device.conn_id, device.addr, device.cp_handle,
939                                 device.cp_ccc_handle, device.cp_ccc_val);
940       SubscribeForNotifications(device.conn_id, device.addr,
941                                 device.active_preset_handle,
942                                 device.active_preset_ccc_handle);
943     }
944 
945     if (osi_property_get_bool("persist.bluetooth.has.always_use_preset_cache",
946                               true) == false) {
947       CpReadAllPresetsOperation(HasCtpOp(
948           device.addr, PresetCtpOpcode::READ_PRESETS,
949           le_audio::has::kStartPresetIndex, le_audio::has::kMaxNumOfPresets));
950     }
951   }
952 
OnEncrypted(HasDevice & device)953   void OnEncrypted(HasDevice& device) {
954     DLOG(INFO) << __func__ << ": " << device.addr;
955 
956     if (device.isGattServiceValid()) {
957       device.is_connecting_actively = false;
958       NotifyHasDeviceValid(device);
959       callbacks_->OnPresetInfo(device.addr, PresetInfoReason::ALL_PRESET_INFO,
960                                device.GetAllPresetInfo());
961       callbacks_->OnActivePresetSelected(device.addr,
962                                          device.currently_active_preset);
963       WriteAllNeededCcc(device);
964     } else {
965       BTA_GATTC_ServiceSearchRequest(device.conn_id,
966                                      &kUuidHearingAccessService);
967     }
968   }
969 
NotifyHasDeviceValid(const HasDevice & device)970   void NotifyHasDeviceValid(const HasDevice& device) {
971     DLOG(INFO) << __func__ << " addr:" << device.addr;
972 
973     std::vector<uint8_t> preset_indices;
974     preset_indices.reserve(device.has_presets.size());
975     for (auto const& preset : device.has_presets) {
976       preset_indices.push_back(preset.GetIndex());
977     }
978 
979     /* Notify that we are ready to go */
980     callbacks_->OnConnectionState(ConnectionState::CONNECTED, device.addr);
981   }
982 
MarkDeviceValidIfInInitialDiscovery(HasDevice & device)983   void MarkDeviceValidIfInInitialDiscovery(HasDevice& device) {
984     if (device.isGattServiceValid()) return;
985 
986     --device.gatt_svc_validation_steps;
987 
988     if (device.isGattServiceValid()) {
989       device.is_connecting_actively = false;
990 
991       std::vector<uint8_t> presets_bin;
992       if (device.SerializePresets(presets_bin)) {
993         btif_storage_add_leaudio_has_device(device.addr, presets_bin,
994                                             device.GetFeatures(),
995                                             device.currently_active_preset);
996       }
997       NotifyHasDeviceValid(device);
998     }
999   }
1000 
OnGattWriteCcc(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,void * user_data)1001   void OnGattWriteCcc(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
1002                       void* user_data) {
1003     DLOG(INFO) << __func__ << ": handle=" << loghex(handle);
1004 
1005     auto device = GetDevice(conn_id);
1006     if (!device) {
1007       LOG(ERROR) << __func__ << ": unknown conn_id=" << loghex(conn_id);
1008       BtaGattQueue::Clean(conn_id);
1009       return;
1010     }
1011 
1012     if (status == GATT_DATABASE_OUT_OF_SYNC) {
1013       LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
1014       ClearDeviceInformationAndStartSearch(device);
1015       return;
1016     }
1017 
1018     HasGattOpContext context(user_data);
1019     bool enabling_ntf = context.context_flags &
1020                         HasGattOpContext::kContextFlagsEnableNotification;
1021 
1022     if (handle == device->features_ccc_handle) {
1023       if (status == GATT_SUCCESS)
1024         device->features_notifications_enabled = enabling_ntf;
1025 
1026     } else if ((handle == device->active_preset_ccc_handle) ||
1027                (handle == device->cp_ccc_handle)) {
1028       /* Both of these CCC are mandatory */
1029       if (enabling_ntf && (status != GATT_SUCCESS)) {
1030         LOG(ERROR) << __func__
1031                    << ": Failed to register for notifications on handle="
1032                    << loghex(handle);
1033         BTA_GATTC_Close(conn_id);
1034         return;
1035       }
1036     }
1037   }
1038 
OnHasNotification(uint16_t conn_id,uint16_t handle,uint16_t len,const uint8_t * value)1039   void OnHasNotification(uint16_t conn_id, uint16_t handle, uint16_t len,
1040                          const uint8_t* value) {
1041     auto device = GetDevice(conn_id);
1042     if (!device) {
1043       LOG(WARNING) << "Skipping unknown device, conn_id=" << loghex(conn_id);
1044       return;
1045     }
1046 
1047     if (handle == device->features_handle) {
1048       OnHasFeaturesValue(&(*device), GATT_SUCCESS, handle, len, value);
1049 
1050     } else if (handle == device->cp_handle) {
1051       OnHasCtpValueNotification(&(*device), len, value);
1052 
1053     } else if (handle == device->active_preset_handle) {
1054       OnHasActivePresetValue(&(*device), GATT_SUCCESS, handle, len, value);
1055     }
1056   }
1057 
1058   /* Gets the device from variant, possibly searching by conn_id */
GetDevice(std::variant<uint16_t,HasDevice * > conn_id_device_variant)1059   HasDevice* GetDevice(
1060       std::variant<uint16_t, HasDevice*> conn_id_device_variant) {
1061     HasDevice* device = nullptr;
1062 
1063     if (std::holds_alternative<HasDevice*>(conn_id_device_variant)) {
1064       device = std::get<HasDevice*>(conn_id_device_variant);
1065     } else {
1066       auto it = std::find_if(
1067           devices_.begin(), devices_.end(),
1068           HasDevice::MatchConnId(std::get<uint16_t>(conn_id_device_variant)));
1069       if (it != devices_.end()) device = &(*it);
1070     }
1071 
1072     return device;
1073   }
1074 
OnHasFeaturesValue(std::variant<uint16_t,HasDevice * > conn_id_device_variant,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void * user_data=nullptr)1075   void OnHasFeaturesValue(
1076       std::variant<uint16_t, HasDevice*> conn_id_device_variant,
1077       tGATT_STATUS status, uint16_t handle, uint16_t len, const uint8_t* value,
1078       void* user_data = nullptr) {
1079     DLOG(INFO) << __func__;
1080 
1081     auto device = GetDevice(conn_id_device_variant);
1082     if (!device) {
1083       LOG(ERROR) << __func__ << ": Unknown device!";
1084       return;
1085     }
1086 
1087     if (status != GATT_SUCCESS) {
1088       if (status == GATT_DATABASE_OUT_OF_SYNC) {
1089         LOG_INFO("Database out of sync for %s",
1090                  device->addr.ToString().c_str());
1091         ClearDeviceInformationAndStartSearch(device);
1092       } else {
1093         LOG_ERROR("Could not read characteristic at handle=0x%04x", handle);
1094         BTA_GATTC_Close(device->conn_id);
1095       }
1096       return;
1097     }
1098 
1099     if (len != 1) {
1100       LOG(ERROR) << "Invalid features value length=" << +len
1101                  << " at handle=" << loghex(handle);
1102       BTA_GATTC_Close(device->conn_id);
1103       return;
1104     }
1105 
1106     /* Store features value */
1107     uint8_t features;
1108     STREAM_TO_UINT8(features, value);
1109     device->UpdateFeatures(features);
1110 
1111     if (device->isGattServiceValid()) {
1112       btif_storage_set_leaudio_has_features(device->addr, features);
1113     }
1114 
1115     /* Journal update */
1116     device->has_journal_.Append(HasJournalRecord(features, true));
1117 
1118     /* When service is not yet validated, report the available device with
1119      * features.
1120      */
1121     if (!device->isGattServiceValid())
1122       callbacks_->OnDeviceAvailable(device->addr, device->GetFeatures());
1123 
1124     /* Notify features */
1125     callbacks_->OnFeaturesUpdate(device->addr, device->GetFeatures());
1126 
1127     MarkDeviceValidIfInInitialDiscovery(*device);
1128   }
1129 
1130   /* Translates GATT statuses to application specific error codes */
GattStatus2SvcErrorCode(tGATT_STATUS status)1131   static ErrorCode GattStatus2SvcErrorCode(tGATT_STATUS status) {
1132     switch (status) {
1133       case 0x80:
1134         /* Invalid Opcode */
1135         /* Unlikely to happen as we would not allow unsupported operations */
1136         return ErrorCode::OPERATION_NOT_SUPPORTED;
1137       case 0x81:
1138         /* Write Name Not Allowed */
1139         return ErrorCode::SET_NAME_NOT_ALLOWED;
1140       case 0x82:
1141         /* Synchronization Not Supported */
1142         return ErrorCode::OPERATION_NOT_SUPPORTED;
1143       case 0x83:
1144         /* Preset Operation Not Possible */
1145         return ErrorCode::OPERATION_NOT_POSSIBLE;
1146       case 0x84:
1147         /* Preset Name Too Long */
1148         return ErrorCode::INVALID_PRESET_NAME_LENGTH;
1149       case 0xFE:
1150         /* Procedure Already in Progress */
1151         return ErrorCode::PROCEDURE_ALREADY_IN_PROGRESS;
1152       default:
1153         return ErrorCode::OPERATION_NOT_POSSIBLE;
1154     }
1155   }
1156 
OnHasPresetReadResponseNotification(HasDevice & device)1157   void OnHasPresetReadResponseNotification(HasDevice& device) {
1158     DLOG(INFO) << __func__;
1159 
1160     while (device.ctp_notifications_.size() != 0) {
1161       auto ntf = device.ctp_notifications_.front();
1162       /* Process only read response events */
1163       if (ntf.opcode != PresetCtpOpcode::READ_PRESET_RESPONSE) break;
1164 
1165       /* Update preset values */
1166       if (ntf.preset.has_value()) {
1167         device.has_presets.erase(ntf.preset->GetIndex());
1168         device.has_presets.insert(ntf.preset.value());
1169       }
1170 
1171       /* We currently do READ_ALL_PRESETS only during the service validation.
1172        * If service is already valid, this must be the READ_PRESET_BY_INDEX.
1173        */
1174       if (device.isGattServiceValid()) {
1175         auto info = device.GetPresetInfo(ntf.preset.value().GetIndex());
1176         if (info.has_value())
1177           callbacks_->OnPresetInfo(
1178               device.addr, PresetInfoReason::PRESET_INFO_REQUEST_RESPONSE,
1179               {{info.value()}});
1180       }
1181 
1182       /* Journal update */
1183       device.has_journal_.Append(HasJournalRecord(ntf));
1184       device.ctp_notifications_.pop_front();
1185     }
1186 
1187     auto in_svc_validation = !device.isGattServiceValid();
1188     MarkDeviceValidIfInInitialDiscovery(device);
1189 
1190     /* We currently do READ_ALL_PRESETS only during the service validation.
1191      * ALL_PRESET_INFO will be sent only during this initial phase.
1192      */
1193     if (in_svc_validation) {
1194       callbacks_->OnPresetInfo(device.addr, PresetInfoReason::ALL_PRESET_INFO,
1195                                device.GetAllPresetInfo());
1196 
1197       /* If this was the last validation step then send the currently active
1198        * preset as well.
1199        */
1200       if (device.isGattServiceValid())
1201         callbacks_->OnActivePresetSelected(device.addr,
1202                                            device.currently_active_preset);
1203     }
1204   }
1205 
OnHasPresetGenericUpdate(HasDevice & device)1206   void OnHasPresetGenericUpdate(HasDevice& device) {
1207     DLOG(ERROR) << __func__;
1208 
1209     std::vector<PresetInfo> updated_infos;
1210     std::vector<PresetInfo> deleted_infos;
1211 
1212     /* Process the entire train of preset changes with generic updates */
1213     while (device.ctp_notifications_.size() != 0) {
1214       auto nt = device.ctp_notifications_.front();
1215 
1216       /* Break if not a generic update anymore */
1217       if (nt.opcode != PresetCtpOpcode::PRESET_CHANGED) break;
1218       if (nt.change_id != PresetCtpChangeId::PRESET_GENERIC_UPDATE) break;
1219 
1220       if (nt.preset.has_value()) {
1221         /* Erase old value if exist */
1222         device.has_presets.erase(nt.preset->GetIndex());
1223 
1224         /* Erase in-between indices */
1225         if (nt.prev_index != 0) {
1226           auto it = device.has_presets.begin();
1227           while (it != device.has_presets.end()) {
1228             if ((it->GetIndex() > nt.prev_index) &&
1229                 (it->GetIndex() < nt.preset->GetIndex())) {
1230               auto info = device.GetPresetInfo(it->GetIndex());
1231               if (info.has_value()) deleted_infos.push_back(info.value());
1232 
1233               it = device.has_presets.erase(it);
1234 
1235             } else {
1236               ++it;
1237             }
1238           }
1239         }
1240         /* Update presets */
1241         device.has_presets.insert(*nt.preset);
1242 
1243         auto info = device.GetPresetInfo(nt.preset->GetIndex());
1244         if (info.has_value()) updated_infos.push_back(info.value());
1245       }
1246 
1247       /* Journal update */
1248       device.has_journal_.Append(HasJournalRecord(nt));
1249       device.ctp_notifications_.pop_front();
1250     }
1251 
1252     if (device.isGattServiceValid()) {
1253       /* Update preset values in the storage */
1254       std::vector<uint8_t> presets_bin;
1255       if (device.SerializePresets(presets_bin)) {
1256         btif_storage_set_leaudio_has_presets(device.addr, presets_bin);
1257       }
1258 
1259       /* Check for the matching coordinated group op. to use group callbacks */
1260       for (auto it = pending_group_operation_timeouts_.rbegin();
1261            it != pending_group_operation_timeouts_.rend(); ++it) {
1262         auto& group_op_coordinator = it->second;
1263 
1264         /* Here we interested only in valid preset name changes */
1265         if (!((group_op_coordinator.operation.opcode ==
1266                PresetCtpOpcode::WRITE_PRESET_NAME) &&
1267               group_op_coordinator.operation.name.has_value()))
1268           continue;
1269 
1270         /* Match preset update results with the triggering operation */
1271         auto renamed_preset_info = std::find_if(
1272             updated_infos.begin(), updated_infos.end(),
1273             [&group_op_coordinator](const auto& info) {
1274               return (group_op_coordinator.operation.name.value() ==
1275                       info.preset_name);
1276             });
1277         if (renamed_preset_info == updated_infos.end()) continue;
1278 
1279         if (group_op_coordinator.SetCompleted(device.addr)) {
1280           group_op_coordinator.preset_info_verification_list.push_back(
1281               *renamed_preset_info);
1282 
1283           /* Call the proper group operation completion callback */
1284           if (group_op_coordinator.IsFullyCompleted()) {
1285             callbacks_->OnPresetInfo(
1286                 group_op_coordinator.operation.GetGroupId(),
1287                 PresetInfoReason::PRESET_INFO_UPDATE, {*renamed_preset_info});
1288             pending_group_operation_timeouts_.erase(it->first);
1289           }
1290 
1291           /* Erase it from the 'updated_infos' since later we'll be sending
1292            * this as a group callback when the other device completes the
1293            * coordinated group name change.
1294            *
1295            * WARNING: There might an issue with callbacks call reordering due to
1296            *  some of them being kept for group callbacks called later, when all
1297            *  the grouped devices complete the coordinated group rename
1298            *  operation. In most cases this should not be a major problem.
1299            */
1300           updated_infos.erase(renamed_preset_info);
1301           break;
1302         }
1303       }
1304 
1305       if (!updated_infos.empty())
1306         callbacks_->OnPresetInfo(
1307             device.addr, PresetInfoReason::PRESET_INFO_UPDATE, updated_infos);
1308 
1309       if (!deleted_infos.empty())
1310         callbacks_->OnPresetInfo(device.addr, PresetInfoReason::PRESET_DELETED,
1311                                  deleted_infos);
1312     }
1313   }
1314 
OnHasPresetAvailabilityChanged(HasDevice & device)1315   void OnHasPresetAvailabilityChanged(HasDevice& device) {
1316     DLOG(INFO) << __func__;
1317 
1318     std::vector<PresetInfo> infos;
1319 
1320     while (device.ctp_notifications_.size() != 0) {
1321       auto nt = device.ctp_notifications_.front();
1322 
1323       /* Process only preset change notifications */
1324       if (nt.opcode != PresetCtpOpcode::PRESET_CHANGED) break;
1325 
1326       auto preset = device.has_presets.extract(nt.index).value();
1327       auto new_props = preset.GetProperties();
1328 
1329       /* Process only the preset availability changes and then notify */
1330       if ((nt.change_id != PresetCtpChangeId::PRESET_AVAILABLE) &&
1331           (nt.change_id != PresetCtpChangeId::PRESET_UNAVAILABLE))
1332         break;
1333 
1334       /* Availability change */
1335       if (nt.change_id == PresetCtpChangeId::PRESET_AVAILABLE) {
1336         new_props |= HasPreset::kPropertyAvailable;
1337       } else {
1338         new_props &= !HasPreset::kPropertyAvailable;
1339       }
1340       device.has_presets.insert(
1341           HasPreset(preset.GetIndex(), new_props, preset.GetName()));
1342 
1343       auto info = device.GetPresetInfo(nt.index);
1344       if (info.has_value()) infos.push_back(info.value());
1345 
1346       /* Journal update */
1347       device.has_journal_.Append(HasJournalRecord(nt));
1348       device.ctp_notifications_.pop_front();
1349     }
1350 
1351     /* Update preset storage */
1352     if (device.isGattServiceValid()) {
1353       std::vector<uint8_t> presets_bin;
1354       if (device.SerializePresets(presets_bin)) {
1355         btif_storage_set_leaudio_has_presets(device.addr, presets_bin);
1356       }
1357     }
1358 
1359     callbacks_->OnPresetInfo(
1360         device.addr, PresetInfoReason::PRESET_AVAILABILITY_CHANGED, infos);
1361   }
1362 
OnHasPresetDeleted(HasDevice & device)1363   void OnHasPresetDeleted(HasDevice& device) {
1364     DLOG(INFO) << __func__;
1365 
1366     std::vector<PresetInfo> infos;
1367     bool is_deleted = false;
1368 
1369     while (device.ctp_notifications_.size() != 0) {
1370       auto nt = device.ctp_notifications_.front();
1371 
1372       /* Process only preset change notifications */
1373       if (nt.opcode != PresetCtpOpcode::PRESET_CHANGED) break;
1374 
1375       /* Process only the deletions and then notify */
1376       if (nt.change_id != PresetCtpChangeId::PRESET_DELETED) break;
1377 
1378       auto info = device.GetPresetInfo(nt.index);
1379       if (info.has_value()) infos.push_back(info.value());
1380 
1381       if (device.has_presets.count(nt.index)) {
1382         is_deleted = true;
1383         device.has_presets.erase(nt.index);
1384       }
1385 
1386       /* Journal update */
1387       device.has_journal_.Append(HasJournalRecord(nt));
1388       device.ctp_notifications_.pop_front();
1389     }
1390 
1391     /* Update preset storage */
1392     if (device.isGattServiceValid()) {
1393       std::vector<uint8_t> presets_bin;
1394       if (device.SerializePresets(presets_bin)) {
1395         btif_storage_set_leaudio_has_presets(device.addr, presets_bin);
1396       }
1397     }
1398 
1399     if (is_deleted)
1400       callbacks_->OnPresetInfo(device.addr, PresetInfoReason::PRESET_DELETED,
1401                                infos);
1402   }
1403 
ProcessCtpNotificationQueue(HasDevice & device)1404   void ProcessCtpNotificationQueue(HasDevice& device) {
1405     std::vector<PresetInfo> infos;
1406 
1407     while (device.ctp_notifications_.size() != 0) {
1408       auto ntf = device.ctp_notifications_.front();
1409       DLOG(INFO) << __func__ << " ntf: " << ntf;
1410 
1411       if (ntf.opcode == PresetCtpOpcode::PRESET_CHANGED) {
1412         switch (ntf.change_id) {
1413           case PresetCtpChangeId::PRESET_GENERIC_UPDATE:
1414             OnHasPresetGenericUpdate(device);
1415             break;
1416           case PresetCtpChangeId::PRESET_AVAILABLE:
1417             OnHasPresetAvailabilityChanged(device);
1418             break;
1419           case PresetCtpChangeId::PRESET_UNAVAILABLE:
1420             OnHasPresetAvailabilityChanged(device);
1421             break;
1422           case PresetCtpChangeId::PRESET_DELETED:
1423             OnHasPresetDeleted(device);
1424             break;
1425           default:
1426             LOG(ERROR) << __func__ << " Invalid notification: " << ntf;
1427             break;
1428         }
1429 
1430       } else if (ntf.opcode == PresetCtpOpcode::READ_PRESET_RESPONSE) {
1431         OnHasPresetReadResponseNotification(device);
1432 
1433       } else {
1434         LOG(ERROR) << __func__ << " Unsupported preset notification: " << ntf;
1435       }
1436     }
1437   }
1438 
OnHasCtpValueNotification(HasDevice * device,uint16_t len,const uint8_t * value)1439   void OnHasCtpValueNotification(HasDevice* device, uint16_t len,
1440                                  const uint8_t* value) {
1441     auto ntf_opt = HasCtpNtf::FromCharacteristicValue(len, value);
1442     if (!ntf_opt.has_value()) {
1443       LOG(ERROR) << __func__
1444                  << " Unhandled notification for device: " << *device;
1445       BTA_GATTC_Close(device->conn_id);
1446       return;
1447     }
1448 
1449     auto ntf = ntf_opt.value();
1450     DLOG(INFO) << __func__ << ntf;
1451 
1452     device->ctp_notifications_.push_back(ntf);
1453     if (ntf.is_last) ProcessCtpNotificationQueue(*device);
1454   }
1455 
OnHasActivePresetValue(std::variant<uint16_t,HasDevice * > conn_id_device_variant,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void * user_data=nullptr)1456   void OnHasActivePresetValue(
1457       std::variant<uint16_t, HasDevice*> conn_id_device_variant,
1458       tGATT_STATUS status, uint16_t handle, uint16_t len, const uint8_t* value,
1459       void* user_data = nullptr) {
1460     DLOG(INFO) << __func__;
1461 
1462     auto device = GetDevice(conn_id_device_variant);
1463     if (!device) {
1464       LOG(ERROR) << "Skipping unknown device!";
1465       return;
1466     }
1467 
1468     if (status != GATT_SUCCESS) {
1469       if (status == GATT_DATABASE_OUT_OF_SYNC) {
1470         LOG_INFO("Database out of sync for %s",
1471                  device->addr.ToString().c_str());
1472         ClearDeviceInformationAndStartSearch(device);
1473       } else {
1474         LOG_ERROR("Could not read characteristic at handle=0x%04x", handle);
1475         BTA_GATTC_Close(device->conn_id);
1476       }
1477     }
1478 
1479     if (len != 1) {
1480       LOG(ERROR) << "Invalid preset value length=" << +len
1481                  << " at handle=" << loghex(handle);
1482       BTA_GATTC_Close(device->conn_id);
1483       return;
1484     }
1485 
1486     /* Get the active preset value */
1487     auto* pp = value;
1488     STREAM_TO_UINT8(device->currently_active_preset, pp);
1489 
1490     if (device->isGattServiceValid()) {
1491       btif_storage_set_leaudio_has_active_preset(
1492           device->addr, device->currently_active_preset);
1493     }
1494 
1495     /* Journal update */
1496     device->has_journal_.Append(
1497         HasJournalRecord(device->currently_active_preset, false));
1498 
1499     /* If svc not marked valid, this might be the last validation step. */
1500     MarkDeviceValidIfInInitialDiscovery(*device);
1501 
1502     if (device->isGattServiceValid()) {
1503       if (!pending_group_operation_timeouts_.empty()) {
1504         for (auto it = pending_group_operation_timeouts_.rbegin();
1505              it != pending_group_operation_timeouts_.rend(); ++it) {
1506           auto& group_op_coordinator = it->second;
1507 
1508           bool matches = false;
1509           switch (group_op_coordinator.operation.opcode) {
1510             case PresetCtpOpcode::SET_ACTIVE_PRESET:
1511               [[fallthrough]];
1512             case PresetCtpOpcode::SET_NEXT_PRESET:
1513               [[fallthrough]];
1514             case PresetCtpOpcode::SET_PREV_PRESET:
1515               [[fallthrough]];
1516             case PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC:
1517               [[fallthrough]];
1518             case PresetCtpOpcode::SET_NEXT_PRESET_SYNC:
1519               [[fallthrough]];
1520             case PresetCtpOpcode::SET_PREV_PRESET_SYNC: {
1521               if (group_op_coordinator.SetCompleted(device->addr)) {
1522                 matches = true;
1523                 break;
1524               }
1525             } break;
1526             default:
1527               /* Ignore */
1528               break;
1529           }
1530           if (group_op_coordinator.IsFullyCompleted()) {
1531             callbacks_->OnActivePresetSelected(
1532                 group_op_coordinator.operation.GetGroupId(),
1533                 device->currently_active_preset);
1534             pending_group_operation_timeouts_.erase(it->first);
1535           }
1536           if (matches) break;
1537         }
1538 
1539       } else {
1540         callbacks_->OnActivePresetSelected(device->addr,
1541                                            device->currently_active_preset);
1542       }
1543     }
1544   }
1545 
DeregisterNotifications(HasDevice & device)1546   void DeregisterNotifications(HasDevice& device) {
1547     /* Deregister from optional features notifications */
1548     if (device.features_ccc_handle != GAP_INVALID_HANDLE) {
1549       BTA_GATTC_DeregisterForNotifications(gatt_if_, device.addr,
1550                                            device.features_handle);
1551     }
1552 
1553     /* Deregister from active presets notifications if presets exist */
1554     if (device.active_preset_ccc_handle != GAP_INVALID_HANDLE) {
1555       BTA_GATTC_DeregisterForNotifications(gatt_if_, device.addr,
1556                                            device.active_preset_handle);
1557     }
1558 
1559     /* Deregister from control point notifications */
1560     if (device.cp_ccc_handle != GAP_INVALID_HANDLE) {
1561       BTA_GATTC_DeregisterForNotifications(gatt_if_, device.addr,
1562                                            device.cp_handle);
1563     }
1564   }
1565 
1566   /* Cleans up after the device disconnection */
DoDisconnectCleanUp(HasDevice & device,bool invalidate_gatt_service=true)1567   void DoDisconnectCleanUp(HasDevice& device,
1568                            bool invalidate_gatt_service = true) {
1569     LOG_DEBUG(": device=%s", device.addr.ToString().c_str());
1570 
1571     DeregisterNotifications(device);
1572 
1573     if (device.conn_id != GATT_INVALID_CONN_ID) {
1574       BtaGattQueue::Clean(device.conn_id);
1575       if (invalidate_gatt_service) device.gatt_svc_validation_steps = 0xFE;
1576     }
1577 
1578     /* Clear pending operations */
1579     auto addr = device.addr;
1580     pending_operations_.erase(
1581         std::remove_if(
1582             pending_operations_.begin(), pending_operations_.end(),
1583             [&addr](auto& el) {
1584               if (std::holds_alternative<RawAddress>(el.addr_or_group)) {
1585                 return std::get<RawAddress>(el.addr_or_group) == addr;
1586               }
1587               return false;
1588             }),
1589         pending_operations_.end());
1590 
1591     device.ConnectionCleanUp();
1592   }
1593 
1594   /* These below are all GATT service discovery, validation, cache & storage */
CacheAttributeHandles(const gatt::Service & service,HasDevice * device)1595   bool CacheAttributeHandles(const gatt::Service& service, HasDevice* device) {
1596     DLOG(INFO) << __func__ << ": device=" << device->addr;
1597 
1598     for (const gatt::Characteristic& charac : service.characteristics) {
1599       if (charac.uuid == kUuidActivePresetIndex) {
1600         /* Find the mandatory CCC descriptor */
1601         uint16_t ccc_handle =
1602             FindCccHandle(device->conn_id, charac.value_handle);
1603         if (ccc_handle == GAP_INVALID_HANDLE) {
1604           LOG(ERROR) << __func__
1605                      << ": no HAS Active Preset CCC descriptor found!";
1606           return false;
1607         }
1608         device->active_preset_ccc_handle = ccc_handle;
1609         device->active_preset_handle = charac.value_handle;
1610 
1611       } else if (charac.uuid == kUuidHearingAidPresetControlPoint) {
1612         /* Find the mandatory CCC descriptor */
1613         uint16_t ccc_handle =
1614             FindCccHandle(device->conn_id, charac.value_handle);
1615         if (ccc_handle == GAP_INVALID_HANDLE) {
1616           LOG(ERROR) << __func__
1617                      << ": no HAS Control Point CCC descriptor found!";
1618           return false;
1619         }
1620         uint8_t ccc_val = 0;
1621         if (charac.properties & GATT_CHAR_PROP_BIT_NOTIFY)
1622           ccc_val |= GATT_CHAR_CLIENT_CONFIG_NOTIFICATION;
1623 
1624         if (charac.properties & GATT_CHAR_PROP_BIT_INDICATE)
1625           ccc_val |= GATT_CHAR_CLIENT_CONFIG_INDICTION;
1626 
1627         if (ccc_val == 0) {
1628           LOG_ERROR("Invalid properties for the control point 0x%02x",
1629                     charac.properties);
1630           return false;
1631         }
1632 
1633         device->cp_ccc_handle = ccc_handle;
1634         device->cp_handle = charac.value_handle;
1635         device->cp_ccc_val = ccc_val;
1636       } else if (charac.uuid == kUuidHearingAidFeatures) {
1637         /* Find the optional CCC descriptor */
1638         uint16_t ccc_handle =
1639             FindCccHandle(device->conn_id, charac.value_handle);
1640         device->features_ccc_handle = ccc_handle;
1641         device->features_handle = charac.value_handle;
1642       }
1643     }
1644     return true;
1645   }
1646 
LoadHasDetailsFromStorage(HasDevice * device)1647   bool LoadHasDetailsFromStorage(HasDevice* device) {
1648     DLOG(INFO) << __func__ << ": device=" << device->addr;
1649 
1650     std::vector<uint8_t> presets_bin;
1651     uint8_t active_preset;
1652 
1653     if (!btif_storage_get_leaudio_has_presets(device->addr, presets_bin,
1654                                               active_preset))
1655       return false;
1656 
1657     if (!HasDevice::DeserializePresets(presets_bin.data(), presets_bin.size(),
1658                                        *device))
1659       return false;
1660 
1661     VLOG(1) << "Loading HAS service details from storage.";
1662 
1663     device->currently_active_preset = active_preset;
1664 
1665     /* Update features and refresh opcode support map */
1666     uint8_t val;
1667     if (btif_storage_get_leaudio_has_features(device->addr, val))
1668       device->UpdateFeatures(val);
1669 
1670     /* With all the details loaded we can already mark it as valid */
1671     device->gatt_svc_validation_steps = 0;
1672     device->is_connecting_actively = false;
1673 
1674     NotifyHasDeviceValid(*device);
1675     callbacks_->OnPresetInfo(device->addr, PresetInfoReason::ALL_PRESET_INFO,
1676                              device->GetAllPresetInfo());
1677     callbacks_->OnActivePresetSelected(device->addr,
1678                                        device->currently_active_preset);
1679     if (device->conn_id == GATT_INVALID_CONN_ID) return true;
1680 
1681     /* Be mistrustful here: write CCC values even remote should have it */
1682     LOG_INFO("Subscribing for notification/indications");
1683     WriteAllNeededCcc(*device);
1684 
1685     return true;
1686   }
1687 
StartInitialHasDetailsReadAndValidation(const gatt::Service & service,HasDevice * device)1688   bool StartInitialHasDetailsReadAndValidation(const gatt::Service& service,
1689                                                HasDevice* device) {
1690     // Validate service structure
1691     if (device->features_handle == GAP_INVALID_HANDLE) {
1692       /* Missing key characteristic */
1693       LOG(ERROR) << __func__ << ": Service has broken structure";
1694       return false;
1695     }
1696 
1697     if (device->cp_handle != GAP_INVALID_HANDLE) {
1698       if (device->active_preset_handle == GAP_INVALID_HANDLE) return false;
1699       if (device->active_preset_ccc_handle == GAP_INVALID_HANDLE) return false;
1700     }
1701 
1702     /* Number of reads or notifications required to validate the service */
1703     device->gatt_svc_validation_steps = 1 + (device->SupportsPresets() ? 2 : 0);
1704 
1705     /* Read the initial features */
1706     BtaGattQueue::ReadCharacteristic(
1707         device->conn_id, device->features_handle,
1708         [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
1709            uint8_t* value, void* user_data) {
1710           if (instance)
1711             instance->OnHasFeaturesValue(conn_id, status, handle, len, value,
1712                                          user_data);
1713         },
1714         nullptr);
1715 
1716     /* Register for features notifications */
1717     if (device->SupportsFeaturesNotification()) {
1718       SubscribeForNotifications(device->conn_id, device->addr,
1719                                 device->features_handle,
1720                                 device->features_ccc_handle);
1721     } else {
1722       LOG(WARNING) << __func__
1723                    << ": server does not support features notification";
1724     }
1725 
1726     /* If Presets are supported we should read them all and subscribe for the
1727      * mandatory active preset index notifications.
1728      */
1729     if (device->SupportsPresets()) {
1730       /* Subscribe for active preset notifications */
1731       SubscribeForNotifications(device->conn_id, device->addr,
1732                                 device->active_preset_handle,
1733                                 device->active_preset_ccc_handle);
1734 
1735       SubscribeForNotifications(device->conn_id, device->addr,
1736                                 device->cp_handle, device->cp_ccc_handle,
1737                                 device->cp_ccc_val);
1738 
1739       /* Get all the presets */
1740       CpReadAllPresetsOperation(HasCtpOp(
1741           device->addr, PresetCtpOpcode::READ_PRESETS,
1742           le_audio::has::kStartPresetIndex, le_audio::has::kMaxNumOfPresets));
1743 
1744       /* Read the current active preset index */
1745       BtaGattQueue::ReadCharacteristic(
1746           device->conn_id, device->active_preset_handle,
1747           [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
1748              uint16_t len, uint8_t* value, void* user_data) {
1749             if (instance)
1750               instance->OnHasActivePresetValue(conn_id, status, handle, len,
1751                                                value, user_data);
1752           },
1753           nullptr);
1754     } else {
1755       LOG(WARNING) << __func__
1756                    << ": server can only report HAS features, other "
1757                       "functionality is disabled";
1758     }
1759 
1760     return true;
1761   }
1762 
OnHasServiceFound(const gatt::Service & service,void * context)1763   bool OnHasServiceFound(const gatt::Service& service, void* context) {
1764     DLOG(INFO) << __func__;
1765 
1766     auto* device = static_cast<HasDevice*>(context);
1767 
1768     /* Initially validate and store GATT service discovery data */
1769     if (!CacheAttributeHandles(service, device)) return false;
1770 
1771     /* If deatails are loaded from storage we are done here */
1772     if (LoadHasDetailsFromStorage(device)) return true;
1773 
1774     /* No storred details - read all the details and validate */
1775     return StartInitialHasDetailsReadAndValidation(service, device);
1776   }
1777 
1778   /* These below are all generic event handlers calling in HAS specific code. */
GattcCallback(tBTA_GATTC_EVT event,tBTA_GATTC * p_data)1779   void GattcCallback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
1780     DLOG(INFO) << __func__ << ": event = " << static_cast<int>(event);
1781 
1782     switch (event) {
1783       case BTA_GATTC_DEREG_EVT:
1784         break;
1785 
1786       case BTA_GATTC_OPEN_EVT:
1787         OnGattConnected(p_data->open);
1788         break;
1789 
1790       case BTA_GATTC_CLOSE_EVT:
1791         OnGattDisconnected(p_data->close);
1792         break;
1793 
1794       case BTA_GATTC_SEARCH_CMPL_EVT:
1795         OnGattServiceSearchComplete(p_data->search_cmpl);
1796         break;
1797 
1798       case BTA_GATTC_NOTIF_EVT:
1799         OnGattNotification(p_data->notify);
1800         break;
1801 
1802       case BTA_GATTC_ENC_CMPL_CB_EVT:
1803         OnLeEncryptionComplete(p_data->enc_cmpl.remote_bda,
1804             BTM_IsEncrypted(p_data->enc_cmpl.remote_bda, BT_TRANSPORT_LE));
1805         break;
1806 
1807       case BTA_GATTC_SRVC_CHG_EVT:
1808         OnGattServiceChangeEvent(p_data->remote_bda);
1809         break;
1810 
1811       case BTA_GATTC_SRVC_DISC_DONE_EVT:
1812         OnGattServiceDiscoveryDoneEvent(p_data->remote_bda);
1813         break;
1814 
1815       default:
1816         break;
1817     }
1818   }
1819 
OnGattConnected(const tBTA_GATTC_OPEN & evt)1820   void OnGattConnected(const tBTA_GATTC_OPEN& evt) {
1821     DLOG(INFO) << __func__ << ": address=" << evt.remote_bda
1822                << ", conn_id=" << evt.conn_id;
1823 
1824     auto device = std::find_if(devices_.begin(), devices_.end(),
1825                                HasDevice::MatchAddress(evt.remote_bda));
1826     if (device == devices_.end()) {
1827       LOG(WARNING) << "Skipping unknown device, address=" << evt.remote_bda;
1828       BTA_GATTC_Close(evt.conn_id);
1829       return;
1830     }
1831 
1832     if (evt.status != GATT_SUCCESS) {
1833       if (!device->is_connecting_actively) {
1834         // acceptlist connection failed, that's ok.
1835         return;
1836       }
1837 
1838       LOG(WARNING) << "Failed to connect to server device";
1839       devices_.erase(device);
1840       callbacks_->OnConnectionState(ConnectionState::DISCONNECTED,
1841                                     evt.remote_bda);
1842       return;
1843     }
1844 
1845     device->conn_id = evt.conn_id;
1846 
1847     if (BTM_SecIsSecurityPending(device->addr)) {
1848       /* if security collision happened, wait for encryption done
1849        * (BTA_GATTC_ENC_CMPL_CB_EVT)
1850        */
1851       return;
1852     }
1853 
1854     /* verify bond */
1855     if (BTM_IsEncrypted(device->addr, BT_TRANSPORT_LE)) {
1856       /* if link has been encrypted */
1857       if (device->isGattServiceValid()) {
1858         instance->OnEncrypted(*device);
1859       } else {
1860         BTA_GATTC_ServiceSearchRequest(device->conn_id,
1861                                        &kUuidHearingAccessService);
1862       }
1863       return;
1864     }
1865 
1866     int result = BTM_SetEncryption(
1867         evt.remote_bda, BT_TRANSPORT_LE,
1868         [](const RawAddress* bd_addr, tBT_TRANSPORT transport, void* p_ref_data,
1869            tBTM_STATUS status) {
1870           if (instance)
1871             instance->OnLeEncryptionComplete(*bd_addr, status == BTM_SUCCESS);
1872         },
1873         nullptr, BTM_BLE_SEC_ENCRYPT);
1874 
1875     DLOG(INFO) << __func__ << ": Encryption request result: " << result;
1876   }
1877 
OnGattDisconnected(const tBTA_GATTC_CLOSE & evt)1878   void OnGattDisconnected(const tBTA_GATTC_CLOSE& evt) {
1879     auto device = std::find_if(devices_.begin(), devices_.end(),
1880                                HasDevice::MatchAddress(evt.remote_bda));
1881     if (device == devices_.end()) {
1882       LOG(WARNING) << "Skipping unknown device disconnect, conn_id="
1883                    << loghex(evt.conn_id);
1884       return;
1885     }
1886     DLOG(INFO) << __func__ << ": device=" << device->addr
1887                << ": reason=" << loghex(static_cast<int>(evt.reason));
1888 
1889     /* Don't notify disconnect state for background connection that failed */
1890     if (device->is_connecting_actively || device->isGattServiceValid())
1891       callbacks_->OnConnectionState(ConnectionState::DISCONNECTED,
1892                                     evt.remote_bda);
1893 
1894     auto peer_disconnected = (evt.reason == GATT_CONN_TIMEOUT) ||
1895                              (evt.reason == GATT_CONN_TERMINATE_PEER_USER);
1896     DoDisconnectCleanUp(*device, peer_disconnected ? false : true);
1897 
1898     /* Connect in background - is this ok? */
1899     if (peer_disconnected)
1900       BTA_GATTC_Open(gatt_if_, device->addr, BTM_BLE_BKG_CONNECT_ALLOW_LIST,
1901                      false);
1902   }
1903 
OnGattServiceSearchComplete(const tBTA_GATTC_SEARCH_CMPL & evt)1904   void OnGattServiceSearchComplete(const tBTA_GATTC_SEARCH_CMPL& evt) {
1905     auto device = GetDevice(evt.conn_id);
1906     if (!device) {
1907       LOG(WARNING) << "Skipping unknown device, conn_id="
1908                    << loghex(evt.conn_id);
1909       return;
1910     }
1911 
1912     DLOG(INFO) << __func__;
1913 
1914     /* Ignore if our service data is valid (service discovery initiated by
1915      * someone else?)
1916      */
1917     if (!device->isGattServiceValid()) {
1918       if (evt.status != GATT_SUCCESS) {
1919         LOG(ERROR) << __func__ << ": Service discovery failed";
1920         BTA_GATTC_Close(device->conn_id);
1921         return;
1922       }
1923 
1924       const std::list<gatt::Service>* all_services =
1925           BTA_GATTC_GetServices(device->conn_id);
1926 
1927       auto service =
1928           std::find_if(all_services->begin(), all_services->end(),
1929                        [](const gatt::Service& svc) {
1930                          return svc.uuid == kUuidHearingAccessService;
1931                        });
1932       if (service == all_services->end()) {
1933         LOG(ERROR) << "No service found";
1934         BTA_GATTC_Close(device->conn_id);
1935         return;
1936       }
1937 
1938       /* Call the service specific verifier callback */
1939       if (!instance->OnHasServiceFound(*service, &(*device))) {
1940         LOG(ERROR) << "Not a valid service!";
1941         BTA_GATTC_Close(device->conn_id);
1942         return;
1943       }
1944     }
1945   }
1946 
OnGattNotification(const tBTA_GATTC_NOTIFY & evt)1947   void OnGattNotification(const tBTA_GATTC_NOTIFY& evt) {
1948     /* Reject invalid lengths */
1949     if (evt.len > GATT_MAX_ATTR_LEN) {
1950       LOG(ERROR) << __func__ << ": rejected BTA_GATTC_NOTIF_EVT. is_notify = "
1951                  << evt.is_notify << ", len=" << static_cast<int>(evt.len);
1952     }
1953     if (!evt.is_notify) BTA_GATTC_SendIndConfirm(evt.conn_id, evt.cid);
1954 
1955     OnHasNotification(evt.conn_id, evt.handle, evt.len, evt.value);
1956   }
1957 
OnLeEncryptionComplete(const RawAddress & address,bool success)1958   void OnLeEncryptionComplete(const RawAddress& address, bool success) {
1959     DLOG(INFO) << __func__ << ": " << address;
1960 
1961     auto device = std::find_if(devices_.begin(), devices_.end(),
1962                                HasDevice::MatchAddress(address));
1963     if (device == devices_.end()) {
1964       LOG(WARNING) << "Skipping unknown device" << address;
1965       return;
1966     }
1967 
1968     if (!success) {
1969       LOG(ERROR) << "Encryption failed for device " << address;
1970 
1971       BTA_GATTC_Close(device->conn_id);
1972       return;
1973     }
1974 
1975     if (device->isGattServiceValid()) {
1976       instance->OnEncrypted(*device);
1977     } else {
1978       BTA_GATTC_ServiceSearchRequest(device->conn_id,
1979                                      &kUuidHearingAccessService);
1980     }
1981   }
1982 
ClearDeviceInformationAndStartSearch(HasDevice * device)1983   void ClearDeviceInformationAndStartSearch(HasDevice* device) {
1984     if (!device) {
1985       LOG_ERROR("Device is null");
1986       return;
1987     }
1988 
1989     LOG_INFO("%s", device->addr.ToString().c_str());
1990 
1991     if (!device->isGattServiceValid()) {
1992       LOG_INFO("Service already invalidated");
1993       return;
1994     }
1995 
1996     /* Invalidate service discovery results */
1997     DeregisterNotifications(*device);
1998     BtaGattQueue::Clean(device->conn_id);
1999     device->ClearSvcData();
2000     btif_storage_remove_leaudio_has(device->addr);
2001     BTA_GATTC_ServiceSearchRequest(device->conn_id, &kUuidHearingAccessService);
2002   }
2003 
OnGattServiceChangeEvent(const RawAddress & address)2004   void OnGattServiceChangeEvent(const RawAddress& address) {
2005     auto device = std::find_if(devices_.begin(), devices_.end(),
2006                                HasDevice::MatchAddress(address));
2007     if (device == devices_.end()) {
2008       LOG(WARNING) << "Skipping unknown device" << address;
2009       return;
2010     }
2011     LOG_INFO("%s", address.ToString().c_str());
2012     ClearDeviceInformationAndStartSearch(&(*device));
2013   }
2014 
OnGattServiceDiscoveryDoneEvent(const RawAddress & address)2015   void OnGattServiceDiscoveryDoneEvent(const RawAddress& address) {
2016     auto device = std::find_if(devices_.begin(), devices_.end(),
2017                                HasDevice::MatchAddress(address));
2018     if (device == devices_.end()) {
2019       LOG(WARNING) << "Skipping unknown device" << address;
2020       return;
2021     }
2022 
2023     DLOG(INFO) << __func__ << ": address=" << address;
2024 
2025     if (!device->isGattServiceValid())
2026       BTA_GATTC_ServiceSearchRequest(device->conn_id,
2027                                      &kUuidHearingAccessService);
2028   }
2029 
FindCccHandle(uint16_t conn_id,uint16_t char_handle)2030   static uint16_t FindCccHandle(uint16_t conn_id, uint16_t char_handle) {
2031     const gatt::Characteristic* p_char =
2032         BTA_GATTC_GetCharacteristic(conn_id, char_handle);
2033     if (!p_char) {
2034       LOG(WARNING) << __func__ << ": No such characteristic: " << char_handle;
2035       return GAP_INVALID_HANDLE;
2036     }
2037 
2038     for (const gatt::Descriptor& desc : p_char->descriptors) {
2039       if (desc.uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG))
2040         return desc.handle;
2041     }
2042 
2043     return GAP_INVALID_HANDLE;
2044   }
2045 
SubscribeForNotifications(uint16_t conn_id,const RawAddress & address,uint16_t value_handle,uint16_t ccc_handle,uint16_t ccc_val=GATT_CHAR_CLIENT_CONFIG_NOTIFICATION)2046   void SubscribeForNotifications(
2047       uint16_t conn_id, const RawAddress& address, uint16_t value_handle,
2048       uint16_t ccc_handle,
2049       uint16_t ccc_val = GATT_CHAR_CLIENT_CONFIG_NOTIFICATION) {
2050     if (value_handle != GAP_INVALID_HANDLE) {
2051       tGATT_STATUS register_status =
2052           BTA_GATTC_RegisterForNotifications(gatt_if_, address, value_handle);
2053       DLOG(INFO) << __func__ << ": BTA_GATTC_RegisterForNotifications, status="
2054                  << loghex(+register_status)
2055                  << " value=" << loghex(value_handle)
2056                  << " ccc=" << loghex(ccc_handle);
2057 
2058       if (register_status != GATT_SUCCESS) return;
2059     }
2060 
2061     std::vector<uint8_t> value(2);
2062     uint8_t* value_ptr = value.data();
2063     UINT16_TO_STREAM(value_ptr, ccc_val);
2064     BtaGattQueue::WriteDescriptor(
2065         conn_id, ccc_handle, std::move(value), GATT_WRITE,
2066         [](uint16_t conn_id, tGATT_STATUS status, uint16_t value_handle,
2067            uint16_t len, const uint8_t* value, void* data) {
2068           if (instance)
2069             instance->OnGattWriteCcc(conn_id, status, value_handle, data);
2070         },
2071         HasGattOpContext(HasGattOpContext::kContextFlagsEnableNotification));
2072   }
2073 
2074   uint8_t gatt_if_;
2075   bluetooth::has::HasClientCallbacks* callbacks_;
2076   std::list<HasDevice> devices_;
2077   std::list<HasCtpOp> pending_operations_;
2078 
2079   typedef std::map<decltype(HasCtpOp::op_id), HasCtpGroupOpCoordinator>
2080       has_operation_timeouts_t;
2081   has_operation_timeouts_t pending_group_operation_timeouts_;
2082 };
2083 
2084 }  // namespace
2085 
2086 alarm_t* HasCtpGroupOpCoordinator::operation_timeout_timer = nullptr;
2087 size_t HasCtpGroupOpCoordinator::ref_cnt = 0u;
__anon8bacd4d91302(void*) 2088 alarm_callback_t HasCtpGroupOpCoordinator::cb = [](void*) {};
2089 
Initialize(bluetooth::has::HasClientCallbacks * callbacks,base::Closure initCb)2090 void HasClient::Initialize(bluetooth::has::HasClientCallbacks* callbacks,
2091                            base::Closure initCb) {
2092   if (instance) {
2093     LOG(ERROR) << "Already initialized!";
2094     return;
2095   }
2096 
2097   HasCtpGroupOpCoordinator::Initialize([](void* p) {
2098     if (instance) instance->OnGroupOpCoordinatorTimeout(p);
2099   });
2100   instance = new HasClientImpl(callbacks, initCb);
2101 }
2102 
IsHasClientRunning()2103 bool HasClient::IsHasClientRunning() { return instance; }
2104 
Get(void)2105 HasClient* HasClient::Get(void) {
2106   CHECK(instance);
2107   return instance;
2108 };
2109 
AddFromStorage(const RawAddress & addr,uint8_t features,uint16_t is_acceptlisted)2110 void HasClient::AddFromStorage(const RawAddress& addr, uint8_t features,
2111                                uint16_t is_acceptlisted) {
2112   if (!instance) {
2113     LOG(ERROR) << "Not initialized yet";
2114   }
2115 
2116   instance->AddFromStorage(addr, features, is_acceptlisted);
2117 };
2118 
CleanUp()2119 void HasClient::CleanUp() {
2120   HasClientImpl* ptr = instance;
2121   instance = nullptr;
2122 
2123   if (ptr) {
2124     ptr->CleanUp();
2125     delete ptr;
2126   }
2127 
2128   HasCtpGroupOpCoordinator::Cleanup();
2129 };
2130 
DebugDump(int fd)2131 void HasClient::DebugDump(int fd) {
2132   dprintf(fd, "Hearing Access Service Client:\n");
2133   if (instance)
2134     instance->Dump(fd);
2135   else
2136     dprintf(fd, "  no instance\n\n");
2137 }
2138