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