csip: Allow to lock only connected devices

Before, CSIP required to have all devices connected in the set to
perform lock procedure.
From now on, CSIP will relax and allow to lock only connected devices
as there is no reason for beeing that strict

Bug: 230426955
Test: atest BluetoothInstrumentationTests
Test: atest --host bluetooth_csis_test
Tag: #stability
Change-Id: I88fc3f2a0e7af67cc3ee7e62813ee3ec08434cd9
Merged-In: I88fc3f2a0e7af67cc3ee7e62813ee3ec08434cd9
(cherry picked from commit 7147c575fa3e2052d28c262bb37873131e5d2910)
diff --git a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
index f094e33..0d455ef 100644
--- a/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
+++ b/android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java
@@ -494,6 +494,9 @@
     public @Nullable UUID lockGroup(
             int groupId, @NonNull IBluetoothCsipSetCoordinatorLockCallback callback) {
         if (callback == null) {
+            if (DBG) {
+                Log.d(TAG, "lockGroup(): " + groupId + ", callback not provided ");
+            }
             return null;
         }
 
@@ -520,12 +523,18 @@
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
+                if (DBG) {
+                    Log.d(TAG, "lockGroup(): " + groupId + ", ERROR_CSIP_GROUP_LOCKED_BY_OTHER ");
+                }
                 return null;
             }
 
             mLocks.put(groupId, new Pair<>(uuid, callback));
         }
 
+        if (DBG) {
+            Log.d(TAG, "lockGroup(): locking group: " + groupId);
+        }
         mCsipSetCoordinatorNativeInterface.groupLockSet(groupId, true);
         return uuid;
     }
@@ -538,6 +547,9 @@
      */
     public void unlockGroup(@NonNull UUID lockUuid) {
         if (lockUuid == null) {
+            if (DBG) {
+                Log.d(TAG, "unlockGroup(): lockUuid is null");
+            }
             return;
         }
 
@@ -546,6 +558,9 @@
                     mLocks.entrySet()) {
                 Pair<UUID, IBluetoothCsipSetCoordinatorLockCallback> uuidCbPair = entry.getValue();
                 if (uuidCbPair.first.equals(lockUuid)) {
+                    if (DBG) {
+                        Log.d(TAG, "unlockGroup(): unlocking ... " + lockUuid);
+                    }
                     mCsipSetCoordinatorNativeInterface.groupLockSet(entry.getKey(), false);
                     return;
                 }
diff --git a/android/leaudio/app/src/main/java/com/android/bluetooth/leaudio/BluetoothProxy.java b/android/leaudio/app/src/main/java/com/android/bluetooth/leaudio/BluetoothProxy.java
index 4bd1dee..1dc1280 100644
--- a/android/leaudio/app/src/main/java/com/android/bluetooth/leaudio/BluetoothProxy.java
+++ b/android/leaudio/app/src/main/java/com/android/bluetooth/leaudio/BluetoothProxy.java
@@ -999,7 +999,10 @@
 
         Log.d("Lock", "lock: " + lock);
         if (lock) {
-            if (mGroupLocks.containsKey(group_id)) return;
+            if (mGroupLocks.containsKey(group_id)) {
+                Log.e("Lock", "group" + group_id + " is already in locking process or locked: " + lock);
+                return;
+            }
 
             UUID uuid = bluetoothCsis.lockGroup(group_id, mExecutor,
                     (int group, int op_status, boolean is_locked) -> {
diff --git a/system/bta/csis/csis_client.cc b/system/bta/csis/csis_client.cc
index afd1b11..71a9d2c 100644
--- a/system/bta/csis/csis_client.cc
+++ b/system/bta/csis/csis_client.cc
@@ -138,6 +138,7 @@
   std::shared_ptr<bluetooth::csis::CsisGroup> AssignCsisGroup(
       const RawAddress& address, int group_id,
       bool create_group_if_non_existing, const bluetooth::Uuid& uuid) {
+    LOG_DEBUG("Device: %s, group_id: %d", address.ToString().c_str(), group_id);
     auto csis_group = FindCsisGroup(group_id);
     if (!csis_group) {
       if (create_group_if_non_existing) {
@@ -322,6 +323,10 @@
     }
 
     CsisLockState target_lock_state = csis_group->GetTargetLockState();
+
+    LOG_DEBUG("Device %s, target lock: %d, status: 0x%02x",
+              device->addr.ToString().c_str(), (int)target_lock_state,
+              (int)status);
     if (target_lock_state == CsisLockState::CSIS_STATE_UNSET) return;
 
     if (status != GATT_SUCCESS &&
@@ -490,6 +495,10 @@
        * can revert lock previously locked devices as per specification.
        */
       auto csis_device = csis_group->GetFirstDevice();
+      while (!csis_device->IsConnected()) {
+        csis_device = csis_group->GetNextDevice(csis_device);
+      }
+
       auto csis_instance = csis_device->GetCsisInstanceByGroupId(group_id);
       LOG_ASSERT(csis_instance) << " csis_instance does not exist!";
       SetLock(csis_device, csis_instance, new_lock_state);
@@ -676,7 +685,9 @@
         if (!instance) {
           stream << "          No csis instance available\n";
         } else {
-          stream << "          rank: " << instance->GetRank() << "\n";
+          stream << "          service handle: "
+                 << loghex(instance->svc_data.start_handle)
+                 << "          rank: " << +instance->GetRank() << "\n";
         }
 
         if (!device->IsConnected()) {
diff --git a/system/bta/csis/csis_types.h b/system/bta/csis/csis_types.h
index 0be02fd..629de77 100644
--- a/system/bta/csis/csis_types.h
+++ b/system/bta/csis/csis_types.h
@@ -27,6 +27,8 @@
 #include "bta_gatt_api.h"
 #include "bta_groups.h"
 #include "gap_api.h"
+#include "gd/common/init_flags.h"
+#include "gd/common/strings.h"
 #include "stack/crypto_toolbox/crypto_toolbox.h"
 
 namespace bluetooth {
@@ -363,15 +365,34 @@
 
   bool IsAvailableForCsisLockOperation(void) {
     int id = group_id_;
-    auto iter = std::find_if(devices_.begin(), devices_.end(), [id](auto& d) {
-      if (!d->IsConnected()) return false;
-      auto inst = d->GetCsisInstanceByGroupId(id);
-      LOG_ASSERT(inst);
-      return inst->GetLockState() == CsisLockState::CSIS_STATE_LOCKED;
-    });
+    int number_of_connected = 0;
+    auto iter = std::find_if(
+        devices_.begin(), devices_.end(), [id, &number_of_connected](auto& d) {
+          if (!d->IsConnected()) {
+            LOG_DEBUG("Device %s is not connected in group %d",
+                      d->addr.ToString().c_str(), id);
+            return false;
+          }
+          auto inst = d->GetCsisInstanceByGroupId(id);
+          if (!inst) {
+            LOG_DEBUG("Instance not available for group %d", id);
+            return false;
+          }
+          number_of_connected++;
+          LOG_DEBUG("Device %s,  lock state: %d", d->addr.ToString().c_str(),
+                    (int)inst->GetLockState());
+          return inst->GetLockState() == CsisLockState::CSIS_STATE_LOCKED;
+        });
 
+    LOG_DEBUG("Locked set: %d, number of connected %d", iter != devices_.end(),
+              number_of_connected);
     /* If there is no locked device, we are good to go */
-    return iter == devices_.end();
+    if (iter != devices_.end()) {
+      LOG_WARN("Device %s is locked ", (*iter)->addr.ToString().c_str());
+      return false;
+    }
+
+    return (number_of_connected > 0);
   }
 
   void SortByCsisRank(void) {