diff options
author | Sven Gothel <[email protected]> | 2020-06-29 04:15:47 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-06-29 04:15:47 +0200 |
commit | dfdfd883f52e8d31c005d0f8ae42bbe6dd60c2b8 (patch) | |
tree | 14c599a06909fca30ceaf5de8946faec492e8c90 | |
parent | e456a087c2e877df949f2dbd7fa95c25fe80a4ee (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.hpp | 2 | ||||
-rw-r--r-- | api/direct_bt/DBTTypes.hpp | 4 | ||||
-rw-r--r-- | api/direct_bt/GATTCharacteristic.hpp | 13 | ||||
-rw-r--r-- | api/direct_bt/GATTDescriptor.hpp | 13 | ||||
-rw-r--r-- | api/direct_bt/GATTHandler.hpp | 6 | ||||
-rw-r--r-- | api/direct_bt/GATTService.hpp | 9 | ||||
-rw-r--r-- | api/direct_bt/dbt_debug.hpp | 18 | ||||
-rw-r--r-- | examples/direct_bt_scanner10/dbt_scanner10.cpp | 131 | ||||
-rw-r--r-- | examples/java/ScannerTinyB10.java | 54 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 8 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattCharacteristic.cxx | 8 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattService.cxx | 8 | ||||
-rw-r--r-- | src/direct_bt/DBTAdapter.cpp | 10 | ||||
-rw-r--r-- | src/direct_bt/DBTDevice.cpp | 5 | ||||
-rw-r--r-- | src/direct_bt/GATTCharacteristic.cpp | 33 | ||||
-rw-r--r-- | src/direct_bt/GATTDescriptor.cpp | 14 | ||||
-rw-r--r-- | src/direct_bt/GATTHandler.cpp | 18 |
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; |