aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-06-29 04:15:47 +0200
committerSven Gothel <[email protected]>2020-06-29 04:15:47 +0200
commitdfdfd883f52e8d31c005d0f8ae42bbe6dd60c2b8 (patch)
tree14c599a06909fca30ceaf5de8946faec492e8c90
parente456a087c2e877df949f2dbd7fa95c25fe80a4ee (diff)
Resolve circular references (p1): C++ GATTHandler, GATTService, pp are not owner of their resepctive backreference
GATTHandler, GATTService, pp are not owner of their resepctive backreference, hence use std::weak_ptr for backreferences in general and validate on usage (nullptr, if destructed). No DBTDevice has been ever destructed after using GATTHandler and discovering all GATT services. In contrast to Java, C++ has no magic GC and hence shared_ptr use_count gets only increased when emplying circular backreferences - none gets destructed. Current ownership relationship is: DBTAdapter -> DBTDevice -> GATTHandler -> GATTService ... each contains a backreference, now using a weak_ptr. Result is that depending on the use-case, DBTDevice instances are destructed: - Using device->remove(): Immediately - No explicit device->remove(): Adapter keeps sharedDevices, destruction occurs at end.
-rw-r--r--api/direct_bt/DBTAdapter.hpp2
-rw-r--r--api/direct_bt/DBTTypes.hpp4
-rw-r--r--api/direct_bt/GATTCharacteristic.hpp13
-rw-r--r--api/direct_bt/GATTDescriptor.hpp13
-rw-r--r--api/direct_bt/GATTHandler.hpp6
-rw-r--r--api/direct_bt/GATTService.hpp9
-rw-r--r--api/direct_bt/dbt_debug.hpp18
-rw-r--r--examples/direct_bt_scanner10/dbt_scanner10.cpp131
-rw-r--r--examples/java/ScannerTinyB10.java54
-rw-r--r--java/jni/direct_bt/DBTDevice.cxx8
-rw-r--r--java/jni/direct_bt/DBTGattCharacteristic.cxx8
-rw-r--r--java/jni/direct_bt/DBTGattService.cxx8
-rw-r--r--src/direct_bt/DBTAdapter.cpp10
-rw-r--r--src/direct_bt/DBTDevice.cpp5
-rw-r--r--src/direct_bt/GATTCharacteristic.cpp33
-rw-r--r--src/direct_bt/GATTDescriptor.cpp14
-rw-r--r--src/direct_bt/GATTHandler.cpp18
17 files changed, 246 insertions, 108 deletions
diff --git a/api/direct_bt/DBTAdapter.hpp b/api/direct_bt/DBTAdapter.hpp
index c493f438..b70f80c4 100644
--- a/api/direct_bt/DBTAdapter.hpp
+++ b/api/direct_bt/DBTAdapter.hpp
@@ -457,6 +457,8 @@ namespace direct_bt {
std::shared_ptr<DBTDevice> findDiscoveredDevice (EUI48 const & mac);
std::string toString() const override;
+
+ void printDevices();
};
} // namespace direct_bt
diff --git a/api/direct_bt/DBTTypes.hpp b/api/direct_bt/DBTTypes.hpp
index 08f8efa6..de827604 100644
--- a/api/direct_bt/DBTTypes.hpp
+++ b/api/direct_bt/DBTTypes.hpp
@@ -65,6 +65,10 @@ namespace direct_bt {
}
public:
+ virtual ~DBTObject() {
+ valid = false;
+ }
+
bool isValid() { return valid; }
};
diff --git a/api/direct_bt/GATTCharacteristic.hpp b/api/direct_bt/GATTCharacteristic.hpp
index caaaa8ad..16aecb1a 100644
--- a/api/direct_bt/GATTCharacteristic.hpp
+++ b/api/direct_bt/GATTCharacteristic.hpp
@@ -72,6 +72,10 @@ namespace direct_bt {
* </p>
*/
class GATTCharacteristic : public JavaUplink {
+ private:
+ /* Characteristics's Service back-reference */
+ std::weak_ptr<GATTService> wbr_service;
+
public:
/** BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.1.1 Characteristic Properties */
enum PropertyBitVal : uint8_t {
@@ -95,9 +99,6 @@ namespace direct_bt {
static std::string getPropertiesString(const PropertyBitVal properties);
static std::vector<std::unique_ptr<std::string>> getPropertiesStringList(const PropertyBitVal properties);
- /* Characteristics's Service back-reference */
- GATTServiceRef service;
-
/**
* Characteristics's Service Handle - key to service's handle range, retrieved from Characteristics data.
* <p>
@@ -136,7 +137,7 @@ namespace direct_bt {
GATTCharacteristic(const GATTServiceRef & service, const uint16_t service_handle, const uint16_t handle,
const PropertyBitVal properties, const uint16_t value_handle, std::shared_ptr<const uuid_t> value_type)
- : service(service), service_handle(service_handle), handle(handle),
+ : wbr_service(service), service_handle(service_handle), handle(handle),
properties(properties), value_handle(value_handle), value_type(value_type) {}
std::string get_java_class() const override {
@@ -146,7 +147,9 @@ namespace direct_bt {
return std::string(JAVA_DBT_PACKAGE "DBTGattCharacteristic");
}
- std::shared_ptr<DBTDevice> getDevice();
+ std::shared_ptr<GATTService> getService() const { return wbr_service.lock(); }
+
+ std::shared_ptr<DBTDevice> getDevice() const;
bool hasProperties(const PropertyBitVal v) const { return v == ( properties & v ); }
diff --git a/api/direct_bt/GATTDescriptor.hpp b/api/direct_bt/GATTDescriptor.hpp
index 3c847f20..5aa75656 100644
--- a/api/direct_bt/GATTDescriptor.hpp
+++ b/api/direct_bt/GATTDescriptor.hpp
@@ -60,6 +60,10 @@ namespace direct_bt {
* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3 Characteristic Descriptor
*/
class GATTDescriptor : public JavaUplink {
+ private:
+ /* Characteristic Descriptor's Characteristic back-reference */
+ std::weak_ptr<GATTCharacteristic> wbr_characteristic;
+
public:
static const uuid16_t TYPE_EXT_PROP;
static const uuid16_t TYPE_USER_DESC;
@@ -95,9 +99,6 @@ namespace direct_bt {
CUSTOM_CHARACTERISTIC_DESCRIPTION = 0x8888
};
- /* Characteristic Descriptor's Characteristic back-reference */
- GATTCharacteristicRef characteristic;
-
/** Type of descriptor */
std::shared_ptr<const uuid_t> type;
@@ -114,7 +115,7 @@ namespace direct_bt {
GATTDescriptor(const GATTCharacteristicRef & characteristic, const std::shared_ptr<const uuid_t> & type,
const uint16_t handle)
- : characteristic(characteristic), type(type), handle(handle), value(0) {}
+ : wbr_characteristic(characteristic), type(type), handle(handle), value(0) {}
std::string get_java_class() const override {
return java_class();
@@ -123,7 +124,9 @@ namespace direct_bt {
return std::string(JAVA_DBT_PACKAGE "DBTGattDescriptor");
}
- std::shared_ptr<DBTDevice> getDevice();
+ std::shared_ptr<GATTCharacteristic> getCharacteristic() const { return wbr_characteristic.lock(); }
+
+ std::shared_ptr<DBTDevice> getDevice() const;
virtual std::string toString() const {
return "[type 0x"+type->toString()+", handle "+uint16HexString(handle)+", value["+value.toString()+"]]";
diff --git a/api/direct_bt/GATTHandler.hpp b/api/direct_bt/GATTHandler.hpp
index 4652a4f2..8ad5c78f 100644
--- a/api/direct_bt/GATTHandler.hpp
+++ b/api/direct_bt/GATTHandler.hpp
@@ -82,7 +82,9 @@ namespace direct_bt {
static inline int number(const Defaults d) { return static_cast<int>(d); }
private:
- std::shared_ptr<DBTDevice> device;
+ /* GATTHandle's Device back-reference */
+ std::weak_ptr<DBTDevice> wbr_device;
+
const std::string deviceString;
std::recursive_mutex mtx_write;
std::recursive_mutex mtx_command;
@@ -109,6 +111,8 @@ namespace direct_bt {
uint16_t usedMTU;
std::vector<GATTServiceRef> services;
+ std::shared_ptr<DBTDevice> getDevice() const { return wbr_device.lock(); }
+
bool validateConnected();
void l2capReaderThreadImpl();
diff --git a/api/direct_bt/GATTService.hpp b/api/direct_bt/GATTService.hpp
index c02628fe..fd70e24a 100644
--- a/api/direct_bt/GATTService.hpp
+++ b/api/direct_bt/GATTService.hpp
@@ -62,10 +62,11 @@ namespace direct_bt {
* which also may include its client config if available.
*/
class GATTService : public JavaUplink {
- public:
+ private:
/* Service's Device back-reference */
- std::shared_ptr<DBTDevice> device;
+ std::weak_ptr<DBTDevice> wbr_device;
+ public:
const bool isPrimary;
/**
@@ -92,7 +93,7 @@ namespace direct_bt {
GATTService(const std::shared_ptr<DBTDevice> &device, const bool isPrimary,
const uint16_t startHandle, const uint16_t endHandle, std::shared_ptr<const uuid_t> type)
- : device(device), isPrimary(isPrimary), startHandle(startHandle), endHandle(endHandle), type(type), characteristicList() {
+ : wbr_device(device), isPrimary(isPrimary), startHandle(startHandle), endHandle(endHandle), type(type), characteristicList() {
characteristicList.reserve(10);
}
@@ -103,6 +104,8 @@ namespace direct_bt {
return std::string(JAVA_DBT_PACKAGE "DBTGattService");
}
+ std::shared_ptr<DBTDevice> getDevice() const { return wbr_device.lock(); }
+
std::string toString() const;
};
diff --git a/api/direct_bt/dbt_debug.hpp b/api/direct_bt/dbt_debug.hpp
index 164d9b8c..c09f9a3e 100644
--- a/api/direct_bt/dbt_debug.hpp
+++ b/api/direct_bt/dbt_debug.hpp
@@ -28,6 +28,9 @@
#include <cstdint>
#include <cstdio>
+#include <vector>
+#include <memory>
+
extern "C" {
#include <errno.h>
}
@@ -60,4 +63,19 @@ extern "C" {
#define INFO_PRINT(...) { fprintf(stderr, "INFO: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); }
+template<class ListElemType>
+inline void printSharedPtrList(std::string prefix, std::vector<std::shared_ptr<ListElemType>> & list) {
+ fprintf(stderr, "%s: Start: %zd elements\n", prefix.c_str(), list.size());
+ int idx = 0;
+ for (auto it = list.begin(); it != list.end(); idx++) {
+ std::shared_ptr<ListElemType> & e = *it;
+ if ( nullptr != e ) {
+ fprintf(stderr, "%s[%d]: useCount %zd, mem %p\n", prefix.c_str(), idx, e.use_count(), e.get());
+ } else {
+ fprintf(stderr, "%s[%d]: NULL\n", prefix.c_str(), idx);
+ }
+ ++it;
+ }
+}
+
#endif /* DBT_DEBUG_HPP_ */
diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp
index 2e11ffba..ed346bb1 100644
--- a/examples/direct_bt_scanner10/dbt_scanner10.cpp
+++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp
@@ -40,11 +40,13 @@ using namespace direct_bt;
static int64_t timestamp_t0;
-static bool MULTI_MEASUREMENTS = true;
+static int MULTI_MEASUREMENTS = 8;
static bool KEEP_CONNECTED = true;
+static bool REMOVE_DEVICE = true;
static bool USE_WHITELIST = false;
+static std::vector<std::shared_ptr<EUI48>> WHITELIST;
static bool SHOW_UPDATE_EVENTS = false;
@@ -129,7 +131,7 @@ class MyAdapterStatusListener : public AdapterStatusListener {
if( !isDeviceProcessing( device->getAddress() ) &&
( waitForDevice == EUI48_ANY_DEVICE ||
( waitForDevice == device->getAddress() &&
- ( MULTI_MEASUREMENTS || !isDeviceProcessed(waitForDevice) )
+ ( 0 < MULTI_MEASUREMENTS || !isDeviceProcessed(waitForDevice) )
)
)
)
@@ -159,7 +161,7 @@ class MyAdapterStatusListener : public AdapterStatusListener {
if( !isDeviceProcessing( device->getAddress() ) &&
( waitForDevice == EUI48_ANY_DEVICE ||
( waitForDevice == device->getAddress() &&
- ( MULTI_MEASUREMENTS || !isDeviceProcessed(waitForDevice) )
+ ( 0 < MULTI_MEASUREMENTS || !isDeviceProcessed(waitForDevice) )
)
)
)
@@ -249,6 +251,8 @@ static void processConnectedDevice(std::shared_ptr<DBTDevice> device) {
//
// GATT Service Processing
//
+ fprintf(stderr, "****** Processing Device: GATT start: %s\n", device->getAddressString().c_str());
+ device->getAdapter().printDevices();
try {
std::vector<GATTServiceRef> primServices = device->getGATTServices(); // implicit GATT connect...
if( 0 == primServices.size() ) {
@@ -320,16 +324,25 @@ exit:
while( device->pingGATT() ) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
- fprintf(stderr, "****** Processing Device: pingGATT failed");
+ fprintf(stderr, "****** Processing Device: pingGATT failed: %s\n", device->getAddressString().c_str());
}
+ fprintf(stderr, "****** Processing Device: disconnecting: %s\n", device->getAddressString().c_str());
device->disconnect(); // will implicitly purge the GATT data, including GATTCharacteristic listener.
while( device->getConnected() ) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
- device->remove();
+ if( REMOVE_DEVICE ) {
+ fprintf(stderr, "****** Processing Device: removing: %s\n", device->getAddressString().c_str());
+ device->remove();
+ }
+ device->getAdapter().printDevices();
removeFromDevicesProcessing(device->getAddress());
+ if( 0 < MULTI_MEASUREMENTS ) {
+ MULTI_MEASUREMENTS--;
+ fprintf(stderr, "****** Processing Device: MULTI_MEASUREMENTS left %d: %s\n", MULTI_MEASUREMENTS, device->getAddressString().c_str());
+ }
fprintf(stderr, "****** Processing Device: End: Success %d on %s; devInProc %zd\n",
success, device->toString().c_str(), devicesInProcessing.size());
if( !USE_WHITELIST && 0 == devicesInProcessing.size() ) {
@@ -340,13 +353,59 @@ exit:
}
}
+void test(int dev_id) {
+ bool done = false;
+
+ timestamp_t0 = getCurrentMilliseconds();
+
+ DBTAdapter adapter(dev_id);
+ if( !adapter.hasDevId() ) {
+ fprintf(stderr, "Default adapter not available.\n");
+ exit(1);
+ }
+ if( !adapter.isValid() ) {
+ fprintf(stderr, "Adapter invalid.\n");
+ exit(1);
+ }
+ fprintf(stderr, "Using adapter: device %s, address %s: %s\n",
+ adapter.getName().c_str(), adapter.getAddressString().c_str(), adapter.toString().c_str());
+
+ adapter.addStatusListener(std::shared_ptr<AdapterStatusListener>(new MyAdapterStatusListener()));
+
+ if( USE_WHITELIST ) {
+ for (auto it = WHITELIST.begin(); it != WHITELIST.end(); ++it) {
+ std::shared_ptr<EUI48> wlmac = *it;
+ bool res = adapter.addDeviceToWhitelist(*wlmac, BDAddressType::BDADDR_LE_PUBLIC, HCIWhitelistConnectType::HCI_AUTO_CONN_ALWAYS);
+ fprintf(stderr, "Added to WHITELIST: res %d, address %s\n", res, wlmac->toString().c_str());
+ }
+ } else {
+ if( !adapter.startDiscovery( true ) ) {
+ perror("Adapter start discovery failed");
+ done = true;
+ }
+ }
+
+ while( !done ) {
+ if( 0 == MULTI_MEASUREMENTS ||
+ ( -1 == MULTI_MEASUREMENTS && waitForDevice != EUI48_ANY_DEVICE && isDeviceProcessed(waitForDevice) )
+ )
+ {
+ fprintf(stderr, "****** EOL Test MULTI_MEASUREMENTS left %d, processed %zd\n",
+ MULTI_MEASUREMENTS, devicesProcessed.size());
+ fprintf(stderr, "****** WaitForDevice %s\n", waitForDevice.toString().c_str());
+ done = true;
+ } else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(3000));
+ }
+ }
+ fprintf(stderr, "****** EOL Adapter's Devices\n");
+ adapter.printDevices();
+}
int main(int argc, char *argv[])
{
int dev_id = 0; // default
bool waitForEnter=false;
- bool done = false;
- std::vector<std::shared_ptr<EUI48>> whitelist;
for(int i=1; i<argc; i++) {
if( !strcmp("-wait", argv[i]) ) {
@@ -362,20 +421,25 @@ int main(int argc, char *argv[])
std::string macstr = std::string(argv[++i]);
std::shared_ptr<EUI48> wlmac( new EUI48(macstr) );
fprintf(stderr, "Whitelist + %s\n", wlmac->toString().c_str());
- whitelist.push_back( wlmac );
+ WHITELIST.push_back( wlmac );
USE_WHITELIST = true;
} else if( !strcmp("-disconnect", argv[i]) ) {
KEEP_CONNECTED = false;
+ } else if( !strcmp("-keepDevice", argv[i]) ) {
+ REMOVE_DEVICE = false;
+ } else if( !strcmp("-count", argv[i]) && argc > (i+1) ) {
+ MULTI_MEASUREMENTS = atoi(argv[++i]);
} else if( !strcmp("-single", argv[i]) ) {
- MULTI_MEASUREMENTS = false;
+ MULTI_MEASUREMENTS = -1;
}
}
fprintf(stderr, "pid %d\n", getpid());
- fprintf(stderr, "Run with '[-dev_id <adapter-index>] [-mac <device_address>] [-disconnect] [-single] (-wl <device_address>)* [-show_update_events]'\n");
+ fprintf(stderr, "Run with '[-dev_id <adapter-index>] [-mac <device_address>] [-disconnect] [-count <number>] [-single] (-wl <device_address>)* [-show_update_events]'\n");
fprintf(stderr, "MULTI_MEASUREMENTS %d\n", MULTI_MEASUREMENTS);
fprintf(stderr, "KEEP_CONNECTED %d\n", KEEP_CONNECTED);
+ fprintf(stderr, "REMOVE_DEVICE %d\n", REMOVE_DEVICE);
fprintf(stderr, "USE_WHITELIST %d\n", USE_WHITELIST);
fprintf(stderr, "dev_id %d\n", dev_id);
fprintf(stderr, "waitForDevice: %s\n", waitForDevice.toString().c_str());
@@ -384,47 +448,8 @@ int main(int argc, char *argv[])
fprintf(stderr, "Press ENTER to continue\n");
getchar();
}
-
- timestamp_t0 = getCurrentMilliseconds();
-
- DBTAdapter adapter(dev_id);
- if( !adapter.hasDevId() ) {
- fprintf(stderr, "Default adapter not available.\n");
- exit(1);
- }
- if( !adapter.isValid() ) {
- fprintf(stderr, "Adapter invalid.\n");
- exit(1);
- }
- fprintf(stderr, "Using adapter: device %s, address %s: %s\n",
- adapter.getName().c_str(), adapter.getAddressString().c_str(), adapter.toString().c_str());
-
- adapter.addStatusListener(std::shared_ptr<AdapterStatusListener>(new MyAdapterStatusListener()));
-
- if( USE_WHITELIST ) {
- for (auto it = whitelist.begin(); it != whitelist.end(); ++it) {
- std::shared_ptr<EUI48> wlmac = *it;
- bool res = adapter.addDeviceToWhitelist(*wlmac, BDAddressType::BDADDR_LE_PUBLIC, HCIWhitelistConnectType::HCI_AUTO_CONN_ALWAYS);
- fprintf(stderr, "Added to whitelist: res %d, address %s\n", res, wlmac->toString().c_str());
- }
- } else {
- if( !adapter.startDiscovery( true ) ) {
- perror("Adapter start discovery failed");
- done = true;
- }
- }
-
- while( !done ) {
- if( waitForDevice != EUI48_ANY_DEVICE &&
- !MULTI_MEASUREMENTS && isDeviceProcessed(waitForDevice)
- )
- {
- fprintf(stderr, "****** WaitForDevice processed %s", waitForDevice.toString().c_str());
- done = true;
- }
- sleep(3);
- }
-
- return 0;
+ fprintf(stderr, "****** TEST start\n");
+ test(dev_id);
+ std::this_thread::sleep_for(std::chrono::milliseconds(3000));
+ fprintf(stderr, "****** TEST end\n");
}
-
diff --git a/examples/java/ScannerTinyB10.java b/examples/java/ScannerTinyB10.java
index d93eacfb..6f724742 100644
--- a/examples/java/ScannerTinyB10.java
+++ b/examples/java/ScannerTinyB10.java
@@ -60,8 +60,9 @@ public class ScannerTinyB10 {
long timestamp_t0;
- boolean MULTI_MEASUREMENTS = true;
+ int MULTI_MEASUREMENTS = 8;
boolean KEEP_CONNECTED = true;
+ boolean REMOVE_DEVICE = true;
boolean USE_WHITELIST = false;
final List<String> whitelist = new ArrayList<String>();
@@ -100,7 +101,7 @@ public class ScannerTinyB10 {
if( !devicesInProcessing.contains( device.getAddress() ) &&
( waitForDevices.isEmpty() ||
( waitForDevices.contains(device.getAddress()) &&
- ( MULTI_MEASUREMENTS || !devicesProcessed.containsAll(waitForDevices) )
+ ( 0 < MULTI_MEASUREMENTS || !devicesProcessed.containsAll(waitForDevices) )
)
)
)
@@ -135,7 +136,7 @@ public class ScannerTinyB10 {
if( !devicesInProcessing.contains( device.getAddress() ) &&
( waitForDevices.isEmpty() ||
( waitForDevices.contains(device.getAddress()) &&
- ( MULTI_MEASUREMENTS || !devicesProcessed.containsAll(waitForDevices) )
+ ( 0 < MULTI_MEASUREMENTS || !devicesProcessed.containsAll(waitForDevices) )
)
)
)
@@ -265,9 +266,10 @@ public class ScannerTinyB10 {
e.printStackTrace();
}
}
- System.err.println("****** Processing Device: pingGATT failed");
+ System.err.println("****** Processing Device: pingGATT failed: "+device.getAddress());
}
+ System.err.println("****** Processing Device: disconnecting: "+device.getAddress());
device.disconnect(); // will implicitly purge the GATT data, including GATTCharacteristic listener.
while( device.getConnected() ) {
try {
@@ -276,9 +278,16 @@ public class ScannerTinyB10 {
e.printStackTrace();
}
}
- device.remove();
+ if( REMOVE_DEVICE ) {
+ System.err.println("****** Processing Device: removing: "+device.getAddress());
+ device.remove();
+ }
devicesInProcessing.remove(device.getAddress());
+ if( 0 < MULTI_MEASUREMENTS ) {
+ MULTI_MEASUREMENTS--;
+ System.err.println("****** Processing Device: MULTI_MEASUREMENTS left "+MULTI_MEASUREMENTS+": "+device.getAddress());
+ }
System.err.println("****** Processing Device: End: Success " + success +
" on " + device.toString() + "; devInProc "+devicesInProcessing.size());
if( !USE_WHITELIST && 0 == devicesInProcessing.size() ) {
@@ -345,23 +354,29 @@ public class ScannerTinyB10 {
}
while( !done ) {
- if( !waitForDevices.isEmpty() &&
- !MULTI_MEASUREMENTS && devicesProcessed.containsAll(waitForDevices)
+ if( 0 == MULTI_MEASUREMENTS ||
+ ( -1 == MULTI_MEASUREMENTS && !waitForDevices.isEmpty() && devicesProcessed.containsAll(waitForDevices) )
)
{
- System.err.println("****** WaitForDevice processed "+Arrays.toString(waitForDevices.toArray()));
+ System.err.println("****** EOL Test MULTI_MEASUREMENTS left "+MULTI_MEASUREMENTS+
+ ", processed "+devicesProcessed.size()+"/"+waitForDevices.size());
+ System.err.println("****** WaitForDevices "+Arrays.toString(waitForDevices.toArray()));
+ System.err.println("****** DevicesProcessed "+Arrays.toString(devicesProcessed.toArray()));
done = true;
+ } else {
+ try {
+ Thread.sleep(3000);
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
}
- try {
- Thread.sleep(3000);
- } catch (final InterruptedException e) {
- e.printStackTrace();
- }
+ System.err.println("****** Garbage Collection.0");
+ System.gc();
+ System.err.println("****** Garbage Collection.X");
}
// All implicit via destructor or shutdown hook!
- // adapter.close();
- // manager.shutdown();
+ // manager.shutdown(); /* implies: adapter.close(); */
}
public static void main(final String[] args) throws InterruptedException {
@@ -387,18 +402,23 @@ public class ScannerTinyB10 {
test.USE_WHITELIST = true;
} else if( arg.equals("-disconnect") ) {
test.KEEP_CONNECTED = false;
+ } else if( arg.equals("-keepDevice") ) {
+ test.REMOVE_DEVICE = false;
+ } else if( arg.equals("-count") && args.length > (i+1) ) {
+ test.MULTI_MEASUREMENTS = Integer.valueOf(args[++i]).intValue();
} else if( arg.equals("-single") ) {
- test.MULTI_MEASUREMENTS = false;
+ test.MULTI_MEASUREMENTS = -1;
} else if( arg.equals("-factory") && args.length > (i+1) ) {
test.factory = Integer.valueOf(args[++i]).intValue();
}
}
- System.err.println("Run with '[-dev_id <adapter-index>] (-mac <device_address>)* [-disconnect] [-single] (-wl <device_address>)* [-show_update_events] [-factory <BluetoothManager-Factory-Implementation-Class>]'");
+ System.err.println("Run with '[-dev_id <adapter-index>] (-mac <device_address>)* [-disconnect] [-count <number>] [-single] (-wl <device_address>)* [-show_update_events] [-factory <BluetoothManager-Factory-Implementation-Class>]'");
}
System.err.println("MULTI_MEASUREMENTS "+test.MULTI_MEASUREMENTS);
System.err.println("KEEP_CONNECTED "+test.KEEP_CONNECTED);
+ System.err.println("REMOVE_DEVICE "+test.REMOVE_DEVICE);
System.err.println("USE_WHITELIST "+test.USE_WHITELIST);
System.err.println("dev_id "+test.dev_id);
System.err.println("waitForDevice: "+Arrays.toString(test.waitForDevices.toArray()));
diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx
index 0a75b77c..20b6060b 100644
--- a/java/jni/direct_bt/DBTDevice.cxx
+++ b/java/jni/direct_bt/DBTDevice.cxx
@@ -355,8 +355,12 @@ jobject Java_direct_1bt_tinyb_DBTDevice_getServicesImpl(JNIEnv *env, jobject obj
std::function<jobject(JNIEnv*, jclass, jmethodID, GATTService*)> ctor_service =
[](JNIEnv *env, jclass clazz, jmethodID clazz_ctor, GATTService *service)->jobject {
// prepare adapter ctor
- JavaGlobalObj::check(service->device->getJavaObject(), E_FILE_LINE);
- jobject jdevice = JavaGlobalObj::GetObject(service->device->getJavaObject());
+ std::shared_ptr<DBTDevice> device = service->getDevice();
+ if( nullptr == device ) {
+ throw IllegalStateException("Service's DBTDevice destructed: "+service->toString(), E_FILE_LINE);
+ }
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+ jobject jdevice = JavaGlobalObj::GetObject(device->getJavaObject());
const jboolean isPrimary = service->isPrimary;
const jstring uuid = from_string_to_jstring(env,
directBTJNISettings.getUnifyUUID128Bit() ? service->type->toUUID128String() :
diff --git a/java/jni/direct_bt/DBTGattCharacteristic.cxx b/java/jni/direct_bt/DBTGattCharacteristic.cxx
index 38a55358..fb966a93 100644
--- a/java/jni/direct_bt/DBTGattCharacteristic.cxx
+++ b/java/jni/direct_bt/DBTGattCharacteristic.cxx
@@ -76,8 +76,12 @@ jobject Java_direct_1bt_tinyb_DBTGattCharacteristic_getDescriptorsImpl(JNIEnv *e
std::function<jobject(JNIEnv*, jclass, jmethodID, GATTDescriptor *)> ctor_desc =
[](JNIEnv *env, jclass clazz, jmethodID clazz_ctor, GATTDescriptor *descriptor)->jobject {
// prepare adapter ctor
- JavaGlobalObj::check(descriptor->characteristic->getJavaObject(), E_FILE_LINE);
- jobject jcharacteristic = JavaGlobalObj::GetObject(descriptor->characteristic->getJavaObject());
+ std::shared_ptr<GATTCharacteristic> characteristic = descriptor->getCharacteristic();
+ if( nullptr == characteristic ) {
+ throw IllegalStateException("Descriptor's GATTCharacteristic destructed: "+descriptor->toString(), E_FILE_LINE);
+ }
+ JavaGlobalObj::check(characteristic->getJavaObject(), E_FILE_LINE);
+ jobject jcharacteristic = JavaGlobalObj::GetObject(characteristic->getJavaObject());
const jstring uuid = from_string_to_jstring(env,
directBTJNISettings.getUnifyUUID128Bit() ? descriptor->type->toUUID128String() :
diff --git a/java/jni/direct_bt/DBTGattService.cxx b/java/jni/direct_bt/DBTGattService.cxx
index 4ded7658..f00f9e2f 100644
--- a/java/jni/direct_bt/DBTGattService.cxx
+++ b/java/jni/direct_bt/DBTGattService.cxx
@@ -76,8 +76,12 @@ jobject Java_direct_1bt_tinyb_DBTGattService_getCharacteristicsImpl(JNIEnv *env,
std::function<jobject(JNIEnv*, jclass, jmethodID, GATTCharacteristic *)> ctor_char =
[](JNIEnv *env, jclass clazz, jmethodID clazz_ctor, GATTCharacteristic *characteristic)->jobject {
// prepare adapter ctor
- JavaGlobalObj::check(characteristic->service->getJavaObject(), E_FILE_LINE);
- jobject jservice = JavaGlobalObj::GetObject(characteristic->service->getJavaObject());
+ std::shared_ptr<GATTService> service = characteristic->getService();
+ if( nullptr == service ) {
+ throw IllegalStateException("Characteristic's GATTService destructed: "+characteristic->toString(), E_FILE_LINE);
+ }
+ JavaGlobalObj::check(service->getJavaObject(), E_FILE_LINE);
+ jobject jservice = JavaGlobalObj::GetObject(service->getJavaObject());
std::vector<std::unique_ptr<std::string>> props = GATTCharacteristic::getPropertiesStringList(characteristic->properties);
unsigned int props_size = props.size();
diff --git a/src/direct_bt/DBTAdapter.cpp b/src/direct_bt/DBTAdapter.cpp
index ecab015a..d8143042 100644
--- a/src/direct_bt/DBTAdapter.cpp
+++ b/src/direct_bt/DBTAdapter.cpp
@@ -196,6 +196,16 @@ DBTAdapter::~DBTAdapter() {
DBG_PRINT("DBTAdapter::dtor: XXX");
}
+void DBTAdapter::printDevices() {
+ const std::lock_guard<std::recursive_mutex> lock0(mtx_connectedDevices);
+ const std::lock_guard<std::recursive_mutex> lock1(mtx_discoveredDevices);
+ const std::lock_guard<std::recursive_mutex> lock2(mtx_sharedDevices);
+
+ printSharedPtrList("SharedDevices", sharedDevices);
+ printSharedPtrList("DiscoveredDevices", discoveredDevices);
+ printSharedPtrList("ConnectedDevices", connectedDevices);
+}
+
std::shared_ptr<NameAndShortName> DBTAdapter::setLocalName(const std::string &name, const std::string &short_name) {
return mgmt.setLocalName(dev_id, name, short_name);
}
diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp
index 02412b49..14fefaab 100644
--- a/src/direct_bt/DBTDevice.cpp
+++ b/src/direct_bt/DBTDevice.cpp
@@ -59,10 +59,11 @@ DBTDevice::DBTDevice(DBTAdapter & a, EInfoReport const & r)
}
DBTDevice::~DBTDevice() {
- DBG_PRINT("DBTDevice::dtor: ... %p %s", this, toString().c_str());
+ DBG_PRINT("DBTDevice::dtor: ... %p %s", this, getAddressString().c_str());
remove();
services.clear();
msd = nullptr;
+ DBG_PRINT("DBTDevice::dtor: XXX %p %s", this, getAddressString().c_str());
}
std::shared_ptr<DBTDevice> DBTDevice::getSharedInstance() const {
@@ -398,7 +399,7 @@ exit:
}
void DBTDevice::remove() {
- disconnect();
+ disconnect(false /* fromDisconnectCB */, false /* ioErrorCause */, HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION);
adapter.removeConnectedDevice(*this); // usually done in DBTAdapter::mgmtEvDeviceDisconnectedHCI
adapter.removeDiscoveredDevice(*this); // usually done in DBTAdapter::mgmtEvDeviceDisconnectedHCI
releaseSharedInstance();
diff --git a/src/direct_bt/GATTCharacteristic.cpp b/src/direct_bt/GATTCharacteristic.cpp
index ebb88d2e..c6de3092 100644
--- a/src/direct_bt/GATTCharacteristic.cpp
+++ b/src/direct_bt/GATTCharacteristic.cpp
@@ -39,10 +39,6 @@
using namespace direct_bt;
-std::shared_ptr<DBTDevice> GATTCharacteristic::getDevice() {
- return service->device;
-}
-
#define CHAR_DECL_PROPS_ENUM(X) \
X(Broadcast,broadcast) \
X(Read,read) \
@@ -67,6 +63,14 @@ std::shared_ptr<DBTDevice> GATTCharacteristic::getDevice() {
#define CASE_TO_STRING2(V,S) case V: return #S;
+std::shared_ptr<DBTDevice> GATTCharacteristic::getDevice() const {
+ std::shared_ptr<GATTService> s = getService();
+ if( nullptr != s ) {
+ return s->getDevice();
+ }
+ return nullptr;
+}
+
std::string GATTCharacteristic::getPropertyString(const PropertyBitVal prop) {
switch(prop) {
CHAR_DECL_PROPS_ENUM(CASE_TO_STRING2)
@@ -106,14 +110,23 @@ std::vector<std::unique_ptr<std::string>> GATTCharacteristic::getPropertiesStrin
}
std::string GATTCharacteristic::toString() const {
- const std::shared_ptr<const uuid_t> & service_uuid = service->type;
- const uint16_t service_handle_end = service->endHandle;
+ std::shared_ptr<const uuid_t> service_uuid;
+ uint16_t service_handle_end = 0xffff;
+ GATTServiceRef serviceRef = getService();
+ std::string service_uuid_str = "";
std::string service_name = "";
std::string char_name = "";
std::string desc_str = ", descr[ ";
- if( uuid_t::UUID16_SZ == service_uuid->getTypeSize() ) {
- const uint16_t uuid16 = (static_cast<const uuid16_t*>(service_uuid.get()))->value;
- service_name = ", "+GattServiceTypeToString(static_cast<GattServiceType>(uuid16));
+
+ if( nullptr != serviceRef ) {
+ service_uuid = serviceRef->type;
+ service_uuid_str = service_uuid->toString();
+ service_handle_end = serviceRef->endHandle;
+
+ if( uuid_t::UUID16_SZ == service_uuid->getTypeSize() ) {
+ const uint16_t uuid16 = (static_cast<const uuid16_t*>(service_uuid.get()))->value;
+ service_name = ", "+GattServiceTypeToString(static_cast<GattServiceType>(uuid16));
+ }
}
if( uuid_t::UUID16_SZ == value_type->getTypeSize() ) {
const uint16_t uuid16 = (static_cast<const uuid16_t*>(value_type.get()))->value;
@@ -126,7 +139,7 @@ std::string GATTCharacteristic::toString() const {
desc_str += " ]";
return "handle "+uint16HexString(handle)+", props "+uint8HexString(properties)+" "+getPropertiesString()+
", value[type 0x"+value_type->toString()+", handle "+uint16HexString(value_handle)+char_name+desc_str+
- "], service[type 0x"+service_uuid->toString()+
+ "], service[type 0x"+service_uuid_str+
", handle[ "+uint16HexString(service_handle)+".."+uint16HexString(service_handle_end)+" ]"+
service_name+" ]";
}
diff --git a/src/direct_bt/GATTDescriptor.cpp b/src/direct_bt/GATTDescriptor.cpp
index 66be0961..5d23c97f 100644
--- a/src/direct_bt/GATTDescriptor.cpp
+++ b/src/direct_bt/GATTDescriptor.cpp
@@ -43,12 +43,19 @@ const uuid16_t GATTDescriptor::TYPE_EXT_PROP(Type::CHARACTERISTIC_EXTENDED_PROPE
const uuid16_t GATTDescriptor::TYPE_USER_DESC(Type::CHARACTERISTIC_USER_DESCRIPTION);
const uuid16_t GATTDescriptor::TYPE_CCC_DESC(Type::CLIENT_CHARACTERISTIC_CONFIGURATION);
-std::shared_ptr<DBTDevice> GATTDescriptor::getDevice() {
- return characteristic->service->device;
+std::shared_ptr<DBTDevice> GATTDescriptor::getDevice() const {
+ std::shared_ptr<GATTCharacteristic> c = getCharacteristic();
+ if( nullptr != c ) {
+ return c->getDevice();
+ }
+ return nullptr;
}
bool GATTDescriptor::readValue(int expectedLength) {
std::shared_ptr<DBTDevice> device = getDevice();
+ if( nullptr == device ) {
+ throw IllegalStateException("Descriptor's device already destructed: "+toString(), E_FILE_LINE);
+ }
std::shared_ptr<GATTHandler> gatt = device->getGATTHandler();
if( nullptr == gatt ) {
throw IllegalStateException("Descriptor's device GATTHandle not connected: "+
@@ -59,6 +66,9 @@ bool GATTDescriptor::readValue(int expectedLength) {
bool GATTDescriptor::writeValue() {
std::shared_ptr<DBTDevice> device = getDevice();
+ if( nullptr == device ) {
+ throw IllegalStateException("Descriptor's device already destructed: "+toString(), E_FILE_LINE);
+ }
std::shared_ptr<GATTHandler> gatt = device->getGATTHandler();
if( nullptr == gatt ) {
throw IllegalStateException("Descriptor's device GATTHandle not connected: "+
diff --git a/src/direct_bt/GATTHandler.cpp b/src/direct_bt/GATTHandler.cpp
index 2eb45f7c..ae33af5c 100644
--- a/src/direct_bt/GATTHandler.cpp
+++ b/src/direct_bt/GATTHandler.cpp
@@ -245,7 +245,7 @@ void GATTHandler::l2capReaderThreadImpl() {
}
GATTHandler::GATTHandler(const std::shared_ptr<DBTDevice> &device, const int replyTimeoutMS)
-: device(device), deviceString(device->getAddressString()), rbuffer(number(Defaults::MAX_ATT_MTU)),
+: wbr_device(device), deviceString(device->getAddressString()), rbuffer(number(Defaults::MAX_ATT_MTU)),
l2cap(device, L2CAP_PSM_UNDEF, L2CAP_CID_ATT), replyTimeoutMS(replyTimeoutMS),
isConnected(false), hasIOError(false),
attPDURing(number(Defaults::ATTPDU_RING_CAPACITY)),
@@ -256,6 +256,7 @@ GATTHandler::GATTHandler(const std::shared_ptr<DBTDevice> &device, const int rep
GATTHandler::~GATTHandler() {
eventListenerList.clear();
disconnect(false /* disconnectDevice */, false /* ioErrorCause */);
+ services.clear();
}
bool GATTHandler::connect() {
@@ -334,6 +335,7 @@ bool GATTHandler::disconnect(const bool disconnectDevice, const bool ioErrorCaus
}
}
}
+ std::shared_ptr<DBTDevice> device = getDevice();
if( disconnectDevice && nullptr != device ) {
// Cleanup device resources, proper connection state
@@ -470,6 +472,11 @@ bool GATTHandler::discoverPrimaryServices(std::vector<GATTServiceRef> & result)
const std::lock_guard<std::recursive_mutex> lock(mtx_command); // RAII-style acquire and relinquish via destructor
PERF_TS_T0();
+ std::shared_ptr<DBTDevice> device = getDevice();
+ if( nullptr == device ) {
+ ERR_PRINT("GATT discoverPrimary: Device destructed: %s", deviceString.c_str());
+ return false;
+ }
bool done=false;
uint16_t startHandle=0x0001;
result.clear();
@@ -872,7 +879,8 @@ std::shared_ptr<GenericAccess> GATTHandler::getGenericAccess(std::vector<GATTCha
for(size_t i=0; i<genericAccessCharDeclList.size(); i++) {
const GATTCharacteristic & charDecl = *genericAccessCharDeclList.at(i);
- if( _GENERIC_ACCESS != *charDecl.service->type ) {
+ std::shared_ptr<GATTService> service = charDecl.getService();
+ if( nullptr == service || _GENERIC_ACCESS != *(service->type) ) {
continue;
}
if( _DEVICE_NAME == *charDecl.value_type ) {
@@ -915,7 +923,8 @@ bool GATTHandler::ping() {
for(size_t i=0; i<genericAccessCharDeclList.size(); i++) {
const GATTCharacteristic & charDecl = *genericAccessCharDeclList.at(i);
- if( _GENERIC_ACCESS != *charDecl.service->type ) {
+ std::shared_ptr<GATTService> service = charDecl.getService();
+ if( nullptr == service || _GENERIC_ACCESS != *(service->type) ) {
continue;
}
if( _APPEARANCE == *charDecl.value_type ) {
@@ -947,7 +956,8 @@ std::shared_ptr<DeviceInformation> GATTHandler::getDeviceInformation(std::vector
for(size_t i=0; i<characteristicDeclList.size(); i++) {
const GATTCharacteristic & charDecl = *characteristicDeclList.at(i);
- if( _DEVICE_INFORMATION != *charDecl.service->type ) {
+ std::shared_ptr<GATTService> service = charDecl.getService();
+ if( nullptr == service || _DEVICE_INFORMATION != *(service->type) ) {
continue;
}
found = true;