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