Skip to content

Commit f86633b

Browse files
authored
[Linux] BLE advertising: Handle adapter removal (project-chip#32434)
* New error code for indicating missing BLE adapter * [Linux] BLE advertising: Handle adapter removal * Return adapter unavailable from RegisterGattApplication too * Account for different timings of adapter removal * Forward error from async request to the application * Handle various scenarios when communicating with BlueZ * Improve readability of error handling blocks
1 parent 77b7a78 commit f86633b

9 files changed

+136
-105
lines changed

docs/ERROR_CODES.md

+1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ This file was **AUTOMATICALLY** generated by
202202

203203
| Decimal | Hex | Name |
204204
|-----------|-------|---------------------------------------------|
205+
| 1025 | 0x401 | `BLE_ERROR_ADAPTER_UNAVAILABLE` |
205206
| 1027 | 0x403 | `BLE_ERROR_NO_CONNECTION_RECEIVED_CALLBACK` |
206207
| 1028 | 0x404 | `BLE_ERROR_CENTRAL_UNSUBSCRIBED` |
207208
| 1029 | 0x405 | `BLE_ERROR_GATT_SUBSCRIBE_FAILED` |

src/ble/BleError.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ bool FormatLayerError(char * buf, uint16_t bufSize, CHIP_ERROR err)
5555
#if !CHIP_CONFIG_SHORT_ERROR_STR
5656
switch (err.AsInteger())
5757
{
58+
case BLE_ERROR_ADAPTER_UNAVAILABLE.AsInteger():
59+
desc = "BLE adapter unavailable";
60+
break;
5861
case BLE_ERROR_NO_CONNECTION_RECEIVED_CALLBACK.AsInteger():
5962
desc = "No chip over BLE connection received callback set";
6063
break;

src/ble/BleError.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,15 @@
4444
* @{
4545
*/
4646

47-
// unused CHIP_BLE_ERROR(0x01)
47+
/**
48+
* @def BLE_ERROR_ADAPTER_UNAVAILABLE
49+
*
50+
* @brief
51+
* Bluetooth LE adapter is (currently) unavailable.
52+
*
53+
*/
54+
#define BLE_ERROR_ADAPTER_UNAVAILABLE CHIP_BLE_ERROR(0x01)
55+
4856
// unused CHIP_BLE_ERROR(0x02)
4957

5058
/**

src/ble/tests/TestBleErrorStr.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ using namespace chip;
4141
// clang-format off
4242
static const CHIP_ERROR kTestElements[] =
4343
{
44+
BLE_ERROR_ADAPTER_UNAVAILABLE,
4445
BLE_ERROR_NO_CONNECTION_RECEIVED_CALLBACK,
4546
BLE_ERROR_CENTRAL_UNSUBSCRIBED,
4647
BLE_ERROR_GATT_SUBSCRIBE_FAILED,

src/platform/Linux/BLEManagerImpl.cpp

+13-12
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEv
287287
PacketBufferHandle::Adopt(apEvent->Platform.BLEIndicationReceived.mData));
288288
break;
289289
case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete:
290-
VerifyOrExit(apEvent->Platform.BLEPeripheralAdvStartComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
290+
SuccessOrExit(err = apEvent->Platform.BLEPeripheralAdvStartComplete.mError);
291291
sInstance.mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
292292
// Do not restart the timer if it is still active. This is to avoid the timer from being restarted
293293
// if the advertising is stopped due to a premature release.
@@ -299,7 +299,7 @@ void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEv
299299
sInstance.mFlags.Set(Flags::kAdvertising);
300300
break;
301301
case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete:
302-
VerifyOrExit(apEvent->Platform.BLEPeripheralAdvStopComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
302+
SuccessOrExit(err = apEvent->Platform.BLEPeripheralAdvStopComplete.mError);
303303
sInstance.mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
304304
DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this);
305305

@@ -316,7 +316,7 @@ void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEv
316316
DriveBLEState();
317317
break;
318318
case DeviceEventType::kPlatformLinuxBLEPeripheralRegisterAppComplete:
319-
VerifyOrExit(apEvent->Platform.BLEPeripheralRegisterAppComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
319+
SuccessOrExit(err = apEvent->Platform.BLEPeripheralRegisterAppComplete.mError);
320320
mFlags.Set(Flags::kAppRegistered);
321321
controlOpComplete = true;
322322
break;
@@ -656,6 +656,7 @@ void BLEManagerImpl::DriveBLEState()
656656
if (err != CHIP_NO_ERROR)
657657
{
658658
ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
659+
DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this);
659660
mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
660661
}
661662
}
@@ -790,27 +791,27 @@ CHIP_ERROR BLEManagerImpl::CancelConnection()
790791
return CHIP_NO_ERROR;
791792
}
792793

793-
void BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(bool aIsSuccess)
794+
void BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(CHIP_ERROR error)
794795
{
795796
ChipDeviceEvent event;
796-
event.Type = DeviceEventType::kPlatformLinuxBLEPeripheralRegisterAppComplete;
797-
event.Platform.BLEPeripheralRegisterAppComplete.mIsSuccess = aIsSuccess;
797+
event.Type = DeviceEventType::kPlatformLinuxBLEPeripheralRegisterAppComplete;
798+
event.Platform.BLEPeripheralRegisterAppComplete.mError = error;
798799
PlatformMgr().PostEventOrDie(&event);
799800
}
800801

801-
void BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(bool aIsSuccess)
802+
void BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(CHIP_ERROR error)
802803
{
803804
ChipDeviceEvent event;
804-
event.Type = DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete;
805-
event.Platform.BLEPeripheralAdvStartComplete.mIsSuccess = aIsSuccess;
805+
event.Type = DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete;
806+
event.Platform.BLEPeripheralAdvStartComplete.mError = error;
806807
PlatformMgr().PostEventOrDie(&event);
807808
}
808809

809-
void BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(bool aIsSuccess)
810+
void BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(CHIP_ERROR error)
810811
{
811812
ChipDeviceEvent event;
812-
event.Type = DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete;
813-
event.Platform.BLEPeripheralAdvStopComplete.mIsSuccess = aIsSuccess;
813+
event.Type = DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete;
814+
event.Platform.BLEPeripheralAdvStopComplete.mError = error;
814815
PlatformMgr().PostEventOrDie(&event);
815816
}
816817

src/platform/Linux/BLEManagerImpl.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ class BLEManagerImpl final : public BLEManager,
9292
static void HandleTXCharCCCDWrite(BLE_CONNECTION_OBJECT user_data);
9393
static void HandleTXComplete(BLE_CONNECTION_OBJECT user_data);
9494

95-
static void NotifyBLEPeripheralRegisterAppComplete(bool aIsSuccess);
96-
static void NotifyBLEPeripheralAdvStartComplete(bool aIsSuccess);
97-
static void NotifyBLEPeripheralAdvStopComplete(bool aIsSuccess);
95+
static void NotifyBLEPeripheralRegisterAppComplete(CHIP_ERROR error);
96+
static void NotifyBLEPeripheralAdvStartComplete(CHIP_ERROR error);
97+
static void NotifyBLEPeripheralAdvStopComplete(CHIP_ERROR error);
9898
static void NotifyBLEPeripheralAdvReleased();
9999

100100
private:

src/platform/Linux/CHIPDevicePlatformEvent.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,15 @@ struct ChipDevicePlatformEvent
9191
} BLEIndicationReceived;
9292
struct
9393
{
94-
bool mIsSuccess;
94+
CHIP_ERROR mError;
9595
} BLEPeripheralRegisterAppComplete;
9696
struct
9797
{
98-
bool mIsSuccess;
98+
CHIP_ERROR mError;
9999
} BLEPeripheralAdvStartComplete;
100100
struct
101101
{
102-
bool mIsSuccess;
102+
CHIP_ERROR mError;
103103
} BLEPeripheralAdvStopComplete;
104104
};
105105
};

src/platform/Linux/bluez/BluezAdvertisement.cpp

+71-61
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <glib-object.h>
2525
#include <glib.h>
2626

27+
#include <ble/BleError.h>
2728
#include <lib/support/CodeUtils.h>
2829
#include <lib/support/logging/CHIPLogging.h>
2930
#include <platform/ConfigurationManager.h>
@@ -109,15 +110,13 @@ CHIP_ERROR BluezAdvertisement::InitImpl()
109110

110111
CHIP_ERROR BluezAdvertisement::Init(const BluezEndpoint & aEndpoint, const char * aAdvUUID, const char * aAdvName)
111112
{
112-
GAutoPtr<char> rootPath;
113-
CHIP_ERROR err;
114-
115-
VerifyOrExit(!mAdv, err = CHIP_ERROR_INCORRECT_STATE;
116-
ChipLogError(DeviceLayer, "FAIL: BLE advertisement already initialized in %s", __func__));
113+
VerifyOrReturnError(!mAdv, CHIP_ERROR_INCORRECT_STATE,
114+
ChipLogError(DeviceLayer, "FAIL: BLE advertisement already initialized in %s", __func__));
117115

118116
mRoot.reset(reinterpret_cast<GDBusObjectManagerServer *>(g_object_ref(aEndpoint.GetGattApplicationObjectManager())));
119117
mAdapter.reset(reinterpret_cast<BluezAdapter1 *>(g_object_ref(aEndpoint.GetAdapter())));
120118

119+
GAutoPtr<char> rootPath;
121120
g_object_get(G_OBJECT(mRoot.get()), "object-path", &rootPath.GetReceiver(), nullptr);
122121
g_snprintf(mAdvPath, sizeof(mAdvPath), "%s/advertising", rootPath.get());
123122
g_strlcpy(mAdvUUID, aAdvUUID, sizeof(mAdvUUID));
@@ -132,15 +131,13 @@ CHIP_ERROR BluezAdvertisement::Init(const BluezEndpoint & aEndpoint, const char
132131
g_snprintf(mAdvName, sizeof(mAdvName), "%s%04x", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, getpid() & 0xffff);
133132
}
134133

135-
err = PlatformMgrImpl().GLibMatterContextInvokeSync(
134+
CHIP_ERROR err = PlatformMgrImpl().GLibMatterContextInvokeSync(
136135
+[](BluezAdvertisement * self) { return self->InitImpl(); }, this);
137-
VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_INCORRECT_STATE,
136+
VerifyOrReturnError(err == CHIP_NO_ERROR, err,
138137
ChipLogError(Ble, "Failed to schedule BLE advertisement Init() on CHIPoBluez thread"));
139138

140139
mIsInitialized = true;
141-
142-
exit:
143-
return err;
140+
return CHIP_NO_ERROR;
144141
}
145142

146143
CHIP_ERROR BluezAdvertisement::SetIntervals(AdvertisingIntervals aAdvIntervals)
@@ -224,39 +221,49 @@ void BluezAdvertisement::Shutdown()
224221

225222
void BluezAdvertisement::StartDone(GObject * aObject, GAsyncResult * aResult)
226223
{
227-
auto * advMgr = reinterpret_cast<BluezLEAdvertisingManager1 *>(aObject);
228224
GAutoPtr<GError> error;
229-
gboolean success = FALSE;
230-
231-
success = bluez_leadvertising_manager1_call_register_advertisement_finish(advMgr, aResult, &error.GetReceiver());
232-
VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterAdvertisement : %s", error->message));
225+
if (!bluez_leadvertising_manager1_call_register_advertisement_finish(reinterpret_cast<BluezLEAdvertisingManager1 *>(aObject),
226+
aResult, &error.GetReceiver()))
227+
{
228+
ChipLogError(DeviceLayer, "FAIL: RegisterAdvertisement: %s", error->message);
229+
switch (error->code)
230+
{
231+
case G_DBUS_ERROR_NO_REPLY: // BlueZ crashed or the D-Bus connection is broken
232+
case G_DBUS_ERROR_SERVICE_UNKNOWN: // BlueZ service is not available on the bus
233+
case G_DBUS_ERROR_UNKNOWN_OBJECT: // Requested BLE adapter is not available
234+
BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(BLE_ERROR_ADAPTER_UNAVAILABLE);
235+
break;
236+
default:
237+
BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(CHIP_ERROR_INTERNAL);
238+
}
239+
return;
240+
}
233241

234242
mIsAdvertising = true;
235243

236-
ChipLogDetail(DeviceLayer, "RegisterAdvertisement complete");
237-
238-
exit:
239-
BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(success == TRUE);
244+
ChipLogDetail(DeviceLayer, "BLE advertisement started successfully");
245+
BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(CHIP_NO_ERROR);
240246
}
241247

242248
CHIP_ERROR BluezAdvertisement::StartImpl()
243249
{
244-
GDBusObject * adapterObject;
245-
GAutoPtr<BluezLEAdvertisingManager1> advMgr;
246-
GVariantBuilder optionsBuilder;
247-
GVariant * options;
250+
VerifyOrReturnError(mAdapter, CHIP_ERROR_UNINITIALIZED);
248251

249-
VerifyOrExit(!mIsAdvertising, ChipLogError(DeviceLayer, "FAIL: Advertising has already been enabled in %s", __func__));
250-
VerifyOrExit(mAdapter, ChipLogError(DeviceLayer, "FAIL: NULL mAdapter in %s", __func__));
252+
// If the adapter configured in the Init() was unplugged, the g_dbus_interface_get_object()
253+
// or bluez_object_get_leadvertising_manager1() might return nullptr (depending on the timing,
254+
// since the D-Bus communication is handled on a separate thread). In such case, we should not
255+
// report internal error, but adapter unavailable, so the application can handle the situation
256+
// properly.
251257

252-
adapterObject = g_dbus_interface_get_object(G_DBUS_INTERFACE(mAdapter.get()));
253-
VerifyOrExit(adapterObject != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapterObject in %s", __func__));
254-
255-
advMgr.reset(bluez_object_get_leadvertising_manager1(reinterpret_cast<BluezObject *>(adapterObject)));
256-
VerifyOrExit(advMgr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
258+
GDBusObject * adapterObject = g_dbus_interface_get_object(reinterpret_cast<GDBusInterface *>(mAdapter.get()));
259+
VerifyOrReturnError(adapterObject != nullptr, BLE_ERROR_ADAPTER_UNAVAILABLE);
260+
GAutoPtr<BluezLEAdvertisingManager1> advMgr(
261+
bluez_object_get_leadvertising_manager1(reinterpret_cast<BluezObject *>(adapterObject)));
262+
VerifyOrReturnError(advMgr, BLE_ERROR_ADAPTER_UNAVAILABLE);
257263

264+
GVariantBuilder optionsBuilder;
258265
g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
259-
options = g_variant_builder_end(&optionsBuilder);
266+
GVariant * options = g_variant_builder_end(&optionsBuilder);
260267

261268
bluez_leadvertising_manager1_call_register_advertisement(
262269
advMgr.get(), mAdvPath, options, nullptr,
@@ -265,51 +272,58 @@ CHIP_ERROR BluezAdvertisement::StartImpl()
265272
},
266273
this);
267274

268-
exit:
269275
return CHIP_NO_ERROR;
270276
}
271277

272278
CHIP_ERROR BluezAdvertisement::Start()
273279
{
274280
VerifyOrReturnError(mIsInitialized, CHIP_ERROR_INCORRECT_STATE);
275-
276-
CHIP_ERROR err = PlatformMgrImpl().GLibMatterContextInvokeSync(
281+
VerifyOrReturnValue(!mIsAdvertising, CHIP_NO_ERROR, ChipLogDetail(DeviceLayer, "BLE advertising already started"));
282+
return PlatformMgrImpl().GLibMatterContextInvokeSync(
277283
+[](BluezAdvertisement * self) { return self->StartImpl(); }, this);
278-
VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_INCORRECT_STATE,
279-
ChipLogError(Ble, "Failed to schedule BLE advertisement Start() on CHIPoBluez thread"));
280-
return err;
281284
}
282285

283286
void BluezAdvertisement::StopDone(GObject * aObject, GAsyncResult * aResult)
284287
{
285-
auto * advMgr = reinterpret_cast<BluezLEAdvertisingManager1 *>(aObject);
286288
GAutoPtr<GError> error;
287-
gboolean success = FALSE;
288-
289-
success = bluez_leadvertising_manager1_call_unregister_advertisement_finish(advMgr, aResult, &error.GetReceiver());
290-
VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnregisterAdvertisement: %s", error->message));
289+
if (!bluez_leadvertising_manager1_call_unregister_advertisement_finish(reinterpret_cast<BluezLEAdvertisingManager1 *>(aObject),
290+
aResult, &error.GetReceiver()))
291+
{
292+
ChipLogError(DeviceLayer, "FAIL: UnregisterAdvertisement: %s", error->message);
293+
switch (error->code)
294+
{
295+
case G_DBUS_ERROR_NO_REPLY: // BlueZ crashed or the D-Bus connection is broken
296+
case G_DBUS_ERROR_SERVICE_UNKNOWN: // BlueZ service is not available on the bus
297+
case G_DBUS_ERROR_UNKNOWN_OBJECT: // Requested BLE adapter is not available
298+
BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(BLE_ERROR_ADAPTER_UNAVAILABLE);
299+
break;
300+
default:
301+
BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(CHIP_ERROR_INTERNAL);
302+
}
303+
return;
304+
}
291305

292306
mIsAdvertising = false;
293307

294-
ChipLogDetail(DeviceLayer, "UnregisterAdvertisement complete");
295-
296-
exit:
297-
BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(success == TRUE);
308+
ChipLogDetail(DeviceLayer, "BLE advertisement stopped successfully");
309+
BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(CHIP_NO_ERROR);
298310
}
299311

300312
CHIP_ERROR BluezAdvertisement::StopImpl()
301313
{
302-
GDBusObject * adapterObject;
303-
GAutoPtr<BluezLEAdvertisingManager1> advMgr;
314+
VerifyOrReturnError(mAdapter, CHIP_ERROR_UNINITIALIZED);
304315

305-
VerifyOrExit(mIsAdvertising, ChipLogError(DeviceLayer, "FAIL: Advertising has already been disabled in %s", __func__));
306-
VerifyOrExit(mAdapter, ChipLogError(DeviceLayer, "FAIL: NULL mAdapter in %s", __func__));
316+
// If the adapter configured in the Init() was unplugged, the g_dbus_interface_get_object()
317+
// or bluez_object_get_leadvertising_manager1() might return nullptr (depending on the timing,
318+
// since the D-Bus communication is handled on a separate thread). In such case, we should not
319+
// report internal error, but adapter unavailable, so the application can handle the situation
320+
// properly.
307321

308-
adapterObject = g_dbus_interface_get_object(G_DBUS_INTERFACE(mAdapter.get()));
309-
VerifyOrExit(adapterObject != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapterObject in %s", __func__));
310-
311-
advMgr.reset(bluez_object_get_leadvertising_manager1(reinterpret_cast<BluezObject *>(adapterObject)));
312-
VerifyOrExit(advMgr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
322+
GDBusObject * adapterObject = g_dbus_interface_get_object(reinterpret_cast<GDBusInterface *>(mAdapter.get()));
323+
VerifyOrReturnError(adapterObject != nullptr, BLE_ERROR_ADAPTER_UNAVAILABLE);
324+
GAutoPtr<BluezLEAdvertisingManager1> advMgr(
325+
bluez_object_get_leadvertising_manager1(reinterpret_cast<BluezObject *>(adapterObject)));
326+
VerifyOrReturnError(advMgr, BLE_ERROR_ADAPTER_UNAVAILABLE);
313327

314328
bluez_leadvertising_manager1_call_unregister_advertisement(
315329
advMgr.get(), mAdvPath, nullptr,
@@ -318,19 +332,15 @@ CHIP_ERROR BluezAdvertisement::StopImpl()
318332
},
319333
this);
320334

321-
exit:
322335
return CHIP_NO_ERROR;
323336
}
324337

325338
CHIP_ERROR BluezAdvertisement::Stop()
326339
{
327340
VerifyOrReturnError(mIsInitialized, CHIP_ERROR_INCORRECT_STATE);
328-
329-
CHIP_ERROR err = PlatformMgrImpl().GLibMatterContextInvokeSync(
341+
VerifyOrReturnValue(mIsAdvertising, CHIP_NO_ERROR, ChipLogDetail(DeviceLayer, "BLE advertising already stopped"));
342+
return PlatformMgrImpl().GLibMatterContextInvokeSync(
330343
+[](BluezAdvertisement * self) { return self->StopImpl(); }, this);
331-
VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_INCORRECT_STATE,
332-
ChipLogError(Ble, "Failed to schedule BLE advertisement Stop() on CHIPoBluez thread"));
333-
return err;
334344
}
335345

336346
} // namespace Internal

0 commit comments

Comments
 (0)