Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin leaks receivers upon connection attempts #528

Closed
b055man opened this issue Sep 17, 2020 · 23 comments
Closed

Plugin leaks receivers upon connection attempts #528

b055man opened this issue Sep 17, 2020 · 23 comments
Labels
bug Something isn't working

Comments

@b055man
Copy link

b055man commented Sep 17, 2020

Observed on version: 2.2.9

After leaving the application reconnecting to a gone device for several hours, the app is no longer operational - it is not possible to register any receivers as app hit the limit of 1000 registered ones.

When it happened once, I later tried to pinpoint the culprit (wasnt't sure if this may be scanning related, or maybe even Wifi portion of the app's functionality) and I reproduced it quickly by repeatedly initiating connections.
Snippet from the code handling the connection:

Log.i(
        'Trying to connect... : ${_peripheral.identifier}, attempt: $retryNum');
    bool connected = false;
    Stopwatch stopwatch = Stopwatch()..start();
    try {final isConnected = await _peripheral.isConnected();
      if (!isConnected) {
        await _peripheral
            .connect(isAutoConnect: autoConnect, refreshGatt: true)
            .timeout(autoConnect ? timeoutAuto : timeoutDirect, onTimeout: () {
          Log.i('Timeout when attempting to connect ${_peripheral.identifier}');
          _peripheral.disconnectOrCancelConnection();
          throw TimeoutException(
              'Failed to connect ${_peripheral.identifier} on time');
        });
      }

Once 1000 connections were reached, this is what I got:

09-17 00:25:20.871  4526  4526 I Fimber.i: [BleDeviceBloc._connect]:   Trying to connect... : 00:1D:96:07:C1:1D, attempt: 1000
09-17 00:25:20.878  4526  4526 D com.polidea.flutter_ble_lib.FlutterBleLibPlugin: on native side observed method: isDeviceConnected
09-17 00:25:20.895  4526  4878 D RxBle#ClientOperationQueue: FINISHED DisconnectOperation(261771749) in 81 ms
09-17 00:25:20.918  4526  4526 D com.polidea.flutter_ble_lib.FlutterBleLibPlugin: on native side observed method: connectToDevice
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: Failed to handle method call
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: rx.exceptions.OnErrorNotImplementedException: Too many receivers, total of 1000, registered for pid: 4526, callerPackage: com.*****
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:386)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:383)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:153)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.NotificationLite.accept(NotificationLite.java:132)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.CachedObservable$ReplayProducer.replay(CachedObservable.java:403)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.CachedObservable$CacheState.dispatch(CachedObservable.java:220)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.CachedObservable$CacheState.onError(CachedObservable.java:201)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.CachedObservable$CacheState$1.onError(CachedObservable.java:175)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorSingle$ParentSubscriber.onError(OperatorSingle.java:129)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorTake$1.onError(OperatorTake.java:66)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorMerge$MergeSubscriber.reportError(OperatorMerge.java:266)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorMerge$MergeSubscriber.checkTerminate(OperatorMerge.java:818)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:579)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:568)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorMerge$InnerSubscriber.onError(OperatorMerge.java:855)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeMap$MapSubscriber.onError(OnSubscribeMap.java:88)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFilter$FilterSubscriber.onError(OnSubscribeFilter.java:90)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.observers.SerializedObserver.onError(SerializedObserver.java:152)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.observers.SerializedSubscriber.onError(SerializedSubscriber.java:78)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.innerError(OnSubscribeConcatMap.java:192)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeConcatMap$ConcatMapInnerSubscriber.onError(OnSubscribeConcatMap.java:340)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeMap$MapSubscriber.onError(OnSubscribeMap.java:88)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10334)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFromArray$FromArrayProducer.slowPath(OnSubscribeFromArray.java:100)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFromArray$FromArrayProducer.request(OnSubscribeFromArray.java:63)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Subscriber.setProducer(Subscriber.java:211)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFromArray.call(OnSubscribeFromArray.java:32)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFromArray.call(OnSubscribeFromArray.java:24)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFilter.call(OnSubscribeFilter.java:45)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFilter.call(OnSubscribeFilter.java:30)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.165  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:248)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:148)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFromArray$FromArrayProducer.fastPath(OnSubscribeFromArray.java:76)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFromArray$FromArrayProducer.request(OnSubscribeFromArray.java:58)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Subscriber.setProducer(Subscriber.java:211)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFromArray.call(OnSubscribeFromArray.java:32)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeFromArray.call(OnSubscribeFromArray.java:24)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.CachedObservable$CacheState.connect(CachedObservable.java:183)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.CachedObservable$CachedSubscribe.call(CachedObservable.java:248)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.CachedObservable$CachedSubscribe.call(CachedObservable.java:230)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.subscribe(Observable.java:10423)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.subscribe(Observable.java:10390)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.subscribe(Observable.java:10165)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.internal.connection.DisconnectionRouter.<init>(DisconnectionRouter.java:70)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.internal.connection.DisconnectionRouter_Factory.get(DisconnectionRouter_Factory.java:33)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.internal.connection.DisconnectionRouter_Factory.get(DisconnectionRouter_Factory.java:10)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at bleshadow.dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.internal.connection.RxBleGattCallback_Factory.get(RxBleGattCallback_Factory.java:33)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.internal.connection.RxBleGattCallback_Factory.get(RxBleGattCallback_Factory.java:8)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at bleshadow.dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.DaggerClientComponent$DeviceComponentImpl$ConnectionComponentImpl.connectOperation(DaggerClientComponent.java:713)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.internal.connection.ConnectorImpl$1.call(ConnectorImpl.java:54)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.internal.connection.ConnectorImpl$1.call(ConnectorImpl.java:38)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.subscribe(Observable.java:10423)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.subscribe(Observable.java:10390)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.subscribe(Observable.java:10298)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.multiplatformbleadapter.BleModule.safeConnectToDevice(BleModule.java:1364)
09-17 00:25:21.219  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.multiplatformbleadapter.BleModule.connectToDevice(BleModule.java:437)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.flutter_ble_lib.delegate.DeviceConnectionDelegate.connectToDevice(DeviceConnectionDelegate.java:106)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.flutter_ble_lib.delegate.DeviceConnectionDelegate.onMethodCall(DeviceConnectionDelegate.java:50)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.flutter_ble_lib.FlutterBleLibPlugin.onMethodCall(FlutterBleLibPlugin.java:98)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:230)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:692)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.os.MessageQueue.nativePollOnce(Native Method)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.os.MessageQueue.next(MessageQueue.java:326)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.os.Looper.loop(Looper.java:170)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.app.ActivityThread.main(ActivityThread.java:6991)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at java.lang.reflect.Method.invoke(Native Method)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:884)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: Caused by: java.lang.IllegalStateException: Too many receivers, total of 1000, registered for pid: 4526, callerPackage: com.motorolasolutions.camera.smartcontrol.debug
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.os.Parcel.createException(Parcel.java:1958)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.os.Parcel.readException(Parcel.java:1918)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.os.Parcel.readException(Parcel.java:1868)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.app.IActivityManager$Stub$Proxy.registerReceiver(IActivityManager.java:3705)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1515)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.app.ContextImpl.registerReceiver(ContextImpl.java:1476)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.app.ContextImpl.registerReceiver(ContextImpl.java:1464)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:623)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.RxBleAdapterStateObservable$1.call(RxBleAdapterStateObservable.java:61)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.polidea.rxandroidble.RxBleAdapterStateObservable$1.call(RxBleAdapterStateObservable.java:47)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeCreate.call(OnSubscribeCreate.java:72)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.internal.operators.OnSubscribeCreate.call(OnSubscribeCreate.java:32)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at rx.Observable.unsafeSubscribe(Observable.java:10327)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	... 84 more
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: Caused by: android.os.RemoteException: Remote stack trace:
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.android.server.am.ActivityManagerService.registerReceiver(ActivityManagerService.java:22002)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.app.IActivityManager$Stub.onTransact$registerReceiver$(IActivityManager.java:10441)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:154)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3548)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 	at com.android.server.am.ActivityManagerServiceEx.onTransact(ActivityManagerServiceEx.java:476)
09-17 00:25:21.298  4526  4526 E MethodChannel#flutter_ble_lib: 
09-17 00:25:21.313  4526  4526 I Fimber.i: [BleDeviceBloc._connect.<anonymous]:   Timeout when attempting to connect 00:1D:96:07:C1:1D

With a profiler from Android Studio I am indeed able to see that there are things that are not released and clearly point to flutter_ble_lib - or rather rxandroidble

image
image

Once that exception is hit, subsequent calls to connect method end instantly with the following error:

BleError (Error code: 203, ATT error code: null, iOS error code: null, Android error code: null, reason: Already connected to device with MAC address 00:1D:96:07:C1:1D, internal message: null, device ID: null, service UUID: null, characteristic UUID: null, descriptor UUID: null)

There doesn't seem to be a way of recovering from this - destroying the client does not help. Only way to resolve that seems to require swiping out the app from the recents application list.

I noticed an issue about a leak in the rxandroidble but it was related to scanning (dariuszseweryn/RxAndroidBle#607) - this one seems to be a bigger issue.

Any hints are appreciated - this is a huge deal for the app I'm working on.

@b055man
Copy link
Author

b055man commented Sep 17, 2020

@mikolak mikolak added the bug Something isn't working label Sep 18, 2020
@dariuszseweryn
Copy link
Collaborator

dariuszseweryn commented Sep 18, 2020

Hi @b055man
Thanks for the report — could you create a minimal project that reproduces the issue?

@b055man
Copy link
Author

b055man commented Sep 18, 2020

@dariuszseweryn
Just tried that using a newly created Flutter example as base with flutter_ble_lib 2.3.0, Flutter: 1.20.3

main.dart

import 'package:ble_lib_leak/connect_ble.dart';
import 'package:flutter/material.dart';
import 'package:flutter_ble_lib/flutter_ble_lib.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  TextEditingController _controller;
  bool _isConnecting = false;

  @override
  void initState() {
    _controller = TextEditingController();
    _controller.value = TextEditingValue(text: '0A:1D:96:07:C1:1D');
    super.initState();
  }

  @override
  void dispose() {
    BleManager().destroyClient();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              controller: _controller,
            ),
            FlatButton(
              child: Text('Start connecting'),
              onPressed: _isConnecting
                  ? null
                  : () {
                      setState(() {
                        _isConnecting = true;
                      });
                      print(_controller.value.text);
                      initiateBurstConnecting(_controller.value.text).then((_) => 
                        _isConnecting = false);
                    },
            )
          ],
        ),
      ),
    );
  }
}

connect_ble.dart

import 'package:flutter_ble_lib/flutter_ble_lib.dart';

Future initiateBurstConnecting(String id) async {
  final bleManager = BleManager();
  await bleManager.createClient();
  await bleManager.setLogLevel(LogLevel.verbose);
  return _connect(bleManager.createUnsafePeripheral(id));
}

Future _connect(Peripheral peripheral, {int retryNum = 1}) async {
  print('Trying to connect... : ${peripheral.identifier}, attempt: $retryNum');
  bool connected = false;
  final isConnected = await peripheral.isConnected();
  if (!isConnected) {
    try {
      await peripheral.connect(
          isAutoConnect: retryNum % 2 == 1,
          refreshGatt: true,
          timeout: Duration(milliseconds: 100));
      connected = await peripheral.isConnected();
      print('Device ${peripheral.identifier} connection result: $connected');
    } catch (e) {
      print('Detailed cause: $e');
      connected = false;
    }
  }
  print(
      'Finished connecting to ${peripheral.identifier}: $connected, retry: $retryNum}');
  return connected || await _connect(peripheral, retryNum: ++retryNum);
}

Press 'start connecting' and wait a bit. You'll get:

D/RxBle#ClientOperationQueue(28933): FINISHED DisconnectOperation(132979214) in 24 ms
E/MethodChannel#flutter_ble_lib(28933): Failed to handle method call
E/MethodChannel#flutter_ble_lib(28933): rx.exceptions.OnErrorNotImplementedException: Too many receivers, total of 1000, registered for pid: 28933, callerPackage: com.example.ble_lib_leak
E/MethodChannel#flutter_ble_lib(28933): 	at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:386)

@dariuszseweryn
Copy link
Collaborator

If you could create a repository which I could clone, build and recreate the issue — that would be perfect

@b055man
Copy link
Author

b055man commented Sep 18, 2020

@b055man
Copy link
Author

b055man commented Sep 23, 2020

@dariuszseweryn were you able to reproduce the issue maybe?

@b055man
Copy link
Author

b055man commented Sep 28, 2020

@mikolak @dariuszseweryn Can I be of any help with addressing this issue?

Thanks,
A.

@dariuszseweryn
Copy link
Collaborator

Hello @b055man
I am recently pretty much saturated with amount of work. Yes, you could help — what we need to do is to perform the test and trace down leaked BroadcastReceivers. It should be fairly simple using LeakCanary — it would probably need a minor native app change to integrate.

@b055man
Copy link
Author

b055man commented Sep 30, 2020

@dariuszseweryn

I'm not sure if LeakCanary is good in tracing leaked Broadcast receivers.. Anyway, I can see a leak warning (pointing to RxBleAdapterStateObservable) if I do even a single connection attempt and trigger the heap dump (simply by leaving the app/putting it in the background). What's also interesting is that if I destroy the BLE client after all connection attempts, there are no leak warnings, yet the receivers are still leaked - the app will crash upon hitting the 1000th connection attempt.

Here's the output from LeakCanary - I hope it can be helpful.
Launching lib/main.dart on H8324 in debug mode...
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk...
Connecting to VM Service at ws://127.0.0.1:64842/A5eQn6v56E0=/ws
D/LeakCanary( 3071): Check for retained object found no objects remaining
W/Gralloc3( 3071): mapper 3.x is not supported
I/flutter ( 3071): 0A:1D:96:07:C1:1D
D/com.polidea.flutter_ble_lib.FlutterBleLibPlugin( 3071): on native side observed method: createClient
I/flutter ( 3071): set log level to verbose
D/com.polidea.flutter_ble_lib.FlutterBleLibPlugin( 3071): on native side observed method: setLogLevel
D/com.polidea.flutter_ble_lib.delegate.LogLevelDelegate( 3071): set log level to: verbose
I/flutter ( 3071): Trying to connect... : 0A:1D:96:07:C1:1D, attempt: 1
D/com.polidea.flutter_ble_lib.FlutterBleLibPlugin( 3071): on native side observed method: isDeviceConnected
D/com.polidea.flutter_ble_lib.FlutterBleLibPlugin( 3071): on native side observed method: connectToDevice
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->objectFieldOffset(Ljava/lang/reflect/Field;)J (greylist,core-platform-api, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->compareAndSwapInt(Ljava/lang/Object;JII)Z (greylist, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->getIntVolatile(Ljava/lang/Object;J)I (greylist, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden field Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe; (greylist, reflection, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->arrayIndexScale(Ljava/lang/Class;)I (greylist, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->arrayBaseOffset(Ljava/lang/Class;)I (greylist,core-platform-api, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->getObjectVolatile(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->putOrderedObject(Ljava/lang/Object;JLjava/lang/Object;)V (greylist, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->putObject(Ljava/lang/Object;JLjava/lang/Object;)V (greylist, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->getLongVolatile(Ljava/lang/Object;J)J (greylist, linking, allowed)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->putOrderedLong(Ljava/lang/Object;JJ)V (greylist, linking, allowed)
D/RxBle#ClientOperationQueue( 3071): QUEUED   ConnectOperation(31049058)
W/le.ble_lib_lea( 3071): Accessing hidden method Lsun/misc/Unsafe;->getObjectVolatile(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
D/RxBle#ClientOperationQueue( 3071): STARTED  ConnectOperation(31049058)
V/RxBle#BleConnectionCompat( 3071): Connecting without reflection
D/BluetoothGatt( 3071): connect() - device: 0A:1D:96:07:C1:1D, auto: true
D/BluetoothGatt( 3071): registerApp()
D/BluetoothGatt( 3071): registerApp() - UUID=fc57a617-b6eb-4d40-8039-0f26d99f09c6
D/RxBle#ClientOperationQueue( 3071): FINISHED ConnectOperation(31049058) in 8 ms
D/BluetoothGatt( 3071): onClientRegistered() - status=0 clientIf=11
D/RxBle#ClientOperationQueue( 3071): QUEUED   DisconnectOperation(12230330)
I/RxBle#ConnectionOperationQueue( 3071): Connection operations queue to be terminated (0A:1D:96:07:C1:1D)
D/RxBle#ClientOperationQueue( 3071): STARTED  DisconnectOperation(12230330)
D/RxBle#Executors$RunnableAdapter( 3071): Terminated.
D/BluetoothGatt( 3071): close()
D/BluetoothGatt( 3071): unregisterApp() - mClientIf=11
D/RxBle#ClientOperationQueue( 3071): FINISHED DisconnectOperation(12230330) in 5 ms
I/flutter ( 3071): Detailed cause: BleError (Error code: 2, ATT error code: null, iOS error code: null, Android error code: null, reason: null, internal message: null, device ID: null, service UUID: null, characteristic UUID: null, descriptor UUID: null)
I/flutter ( 3071): Finished connecting to 0A:1D:96:07:C1:1D: false, retry: 1}
D/LeakCanary( 3071): Scheduling check for retained objects in 5000ms because app became invisible
D/LeakCanary( 3071): Watching instance of com.example.ble_lib_leak.MainActivity (com.example.ble_lib_leak.MainActivity received Activity#onDestroy() callback) with key c43c18c7-3f22-44c8-b4ae-d5dce58c5373
D/LeakCanary( 3071): Ignoring request to check for retained objects (found new object retained), already scheduled in -20ms
I/le.ble_lib_lea( 3071): Explicit concurrent copying GC freed 399(60KB) AllocSpace objects, 0(0B) LOS objects, 24% free, 1908KB/2545KB, paused 66us total 27.894ms
D/LeakCanary( 3071): Check for retained objects found 1 objects, dumping the heap
D/LeakCanary( 3071): WRITE_EXTERNAL_STORAGE permission not granted, ignoring
I/le.ble_lib_lea( 3071): hprof: heap dump "/data/user/0/com.example.ble_lib_leak/files/leakcanary/2020-09-30_22-35-03_352.hprof" starting...
I/le.ble_lib_lea( 3071): hprof: heap dump completed (17MB) in 3.048s objects 240078 objects with stack traces 0
D/LeakCanary( 3071): Analysis in progress, working on: PARSING_HEAP_DUMP
D/LeakCanary( 3071): Analysis in progress, working on: EXTRACTING_METADATA
D/LeakCanary( 3071): Analysis in progress, working on: FINDING_RETAINED_OBJECTS
D/LeakCanary( 3071): Analysis in progress, working on: FINDING_PATHS_TO_RETAINED_OBJECTS
D/LeakCanary( 3071): Setting up flushing for Thread[IntentService[HeapAnalyzerService],5,main]
D/LeakCanary( 3071): Analysis in progress, working on: FINDING_DOMINATORS
D/LeakCanary( 3071): Found 1 retained objects
D/LeakCanary( 3071): Analysis in progress, working on: COMPUTING_NATIVE_RETAINED_SIZE
D/LeakCanary( 3071): Analysis in progress, working on: COMPUTING_RETAINED_SIZE
D/LeakCanary( 3071): Analysis in progress, working on: BUILDING_LEAK_TRACES
D/LeakCanary( 3071): Found 1 paths to retained objects
D/LeakCanary( 3071): Analysis in progress, working on: REPORTING_HEAP_ANALYSIS
D/LeakCanary( 3071): ====================================
D/LeakCanary( 3071): HEAP ANALYSIS RESULT
D/LeakCanary( 3071): ====================================
D/LeakCanary( 3071): 1 APPLICATION LEAKS
D/LeakCanary( 3071):
D/LeakCanary( 3071): References underlined with "~~~" are likely causes.
D/LeakCanary( 3071): Learn more at https://squ.re/leaks.
D/LeakCanary( 3071):
D/LeakCanary( 3071): 47539 bytes retained by leaking objects
D/LeakCanary( 3071): Signature: 80fbdbdf56e375ce1c0ca141253522c45c4dc
D/LeakCanary( 3071): ┬───
D/LeakCanary( 3071): │ GC Root: System class
D/LeakCanary( 3071): │
D/LeakCanary( 3071): ├─ android.provider.FontsContract class
D/LeakCanary( 3071): │    Leaking: NO (FlutterApplication↓ is not leaking and a class is never leaking)
D/LeakCanary( 3071): │    ↓ static FontsContract.sContext
D/LeakCanary( 3071): ├─ io.flutter.app.FlutterApplication instance
D/LeakCanary( 3071): │    Leaking: NO (Application is a singleton)
D/LeakCanary( 3071): │    ↓ FlutterApplication.mLoadedApk
D/LeakCanary( 3071): │                         ~~~~~~~~~~
D/LeakCanary( 3071): ├─ android.app.LoadedApk instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ LoadedApk.mReceivers
D/LeakCanary( 3071): │                ~~~~~~~~~~
D/LeakCanary( 3071): ├─ android.util.ArrayMap instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ ArrayMap.mArray
D/LeakCanary( 3071): │               ~~~~~~
D/LeakCanary( 3071): ├─ java.lang.Object[] array
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ Object[].[1]
D/LeakCanary( 3071): │               ~~~
D/LeakCanary( 3071): ├─ android.util.ArrayMap instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ ArrayMap.mArray
D/LeakCanary( 3071): │               ~~~~~~
D/LeakCanary( 3071): ├─ java.lang.Object[] array
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ Object[].[0]
D/LeakCanary( 3071): │               ~~~
D/LeakCanary( 3071): ├─ com.polidea.rxandroidble.RxBleAdapterStateObservable$1$1 instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    Anonymous subclass of android.content.BroadcastReceiver
D/LeakCanary( 3071): │    ↓ RxBleAdapterStateObservable$1$1.val$emitter
D/LeakCanary( 3071): │                                      ~~~~~~~~~~~
D/LeakCanary( 3071): ├─ rx.internal.operators.OnSubscribeCreate$LatestEmitter instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ OnSubscribeCreate$LatestEmitter.actual
D/LeakCanary( 3071): │                                      ~~~~~~
D/LeakCanary( 3071): ├─ rx.internal.operators.OnSubscribeMap$MapSubscriber instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ OnSubscribeMap$MapSubscriber.mapper
D/LeakCanary( 3071): │                                   ~~~~~~
D/LeakCanary( 3071): ├─ com.polidea.multiplatformbleadapter.BleModule$13 instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    Anonymous class implementing rx.functions.Func1
D/LeakCanary( 3071): │    ↓ BleModule$13.this$0
D/LeakCanary( 3071): │                   ~~~~~~
D/LeakCanary( 3071): ├─ com.polidea.multiplatformbleadapter.BleModule instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ BleModule.connectingDevices
D/LeakCanary( 3071): │                ~~~~~~~~~~~~~~~~~
D/LeakCanary( 3071): ├─ com.polidea.multiplatformbleadapter.utils.DisposableMap instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ DisposableMap.subscriptions
D/LeakCanary( 3071): │                    ~~~~~~~~~~~~~
D/LeakCanary( 3071): ├─ java.util.HashMap instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ HashMap.table
D/LeakCanary( 3071): │              ~~~~~
D/LeakCanary( 3071): ├─ java.util.HashMap$Node[] array
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ HashMap$Node[].[0]
D/LeakCanary( 3071): │                     ~~~
D/LeakCanary( 3071): ├─ java.util.HashMap$Node instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ HashMap$Node.value
D/LeakCanary( 3071): │                   ~~~~~
D/LeakCanary( 3071): ├─ rx.observers.SafeSubscriber instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ SafeSubscriber.actual
D/LeakCanary( 3071): │                     ~~~~~~
D/LeakCanary( 3071): ├─ rx.internal.util.ObserverSubscriber instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ ObserverSubscriber.observer
D/LeakCanary( 3071): │                         ~~~~~~~~
D/LeakCanary( 3071): ├─ com.polidea.multiplatformbleadapter.BleModule$27 instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    Anonymous class implementing rx.Observer
D/LeakCanary( 3071): │    ↓ BleModule$27.val$safeExecutor
D/LeakCanary( 3071): │                   ~~~~~~~~~~~~~~~~
D/LeakCanary( 3071): ├─ com.polidea.multiplatformbleadapter.utils.SafeExecutor instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ SafeExecutor.errorCallback
D/LeakCanary( 3071): │                   ~~~~~~~~~~~~~
D/LeakCanary( 3071): ├─ com.polidea.flutter_ble_lib.delegate.DeviceConnectionDelegate$5 instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    Anonymous class implementing com.polidea.multiplatformbleadapter.OnErrorCallback
D/LeakCanary( 3071): │    ↓ DeviceConnectionDelegate$5.val$safeMainThreadResolver
D/LeakCanary( 3071): │                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~
D/LeakCanary( 3071): ├─ com.polidea.flutter_ble_lib.SafeMainThreadResolver instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ SafeMainThreadResolver.onErrorCallback
D/LeakCanary( 3071): │                             ~~~~~~~~~~~~~~~
D/LeakCanary( 3071): ├─ com.polidea.flutter_ble_lib.delegate.DeviceConnectionDelegate$2 instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    Anonymous class implementing com.polidea.multiplatformbleadapter.OnErrorCallback
D/LeakCanary( 3071): │    ↓ DeviceConnectionDelegate$2.val$result
D/LeakCanary( 3071): │                                 ~~~~~~~~~~
D/LeakCanary( 3071): ├─ io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1 instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    Anonymous class implementing io.flutter.plugin.common.MethodChannel$Result
D/LeakCanary( 3071): │    ↓ MethodChannel$IncomingMethodCallHandler$1.val$reply
D/LeakCanary( 3071): │                                                ~~~~~~~~~
D/LeakCanary( 3071): ├─ io.flutter.embedding.engine.dart.DartMessenger$Reply instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ DartMessenger$Reply.flutterJNI
D/LeakCanary( 3071): │                          ~~~~~~~~~~
D/LeakCanary( 3071): ├─ io.flutter.embedding.engine.FlutterJNI instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ FlutterJNI.localizationPlugin
D/LeakCanary( 3071): │                 ~~~~~~~~~~~~~~~~~~
D/LeakCanary( 3071): ├─ io.flutter.plugin.localization.LocalizationPlugin instance
D/LeakCanary( 3071): │    Leaking: UNKNOWN
D/LeakCanary( 3071): │    ↓ LocalizationPlugin.context
D/LeakCanary( 3071): │                         ~~~~~~~
D/LeakCanary( 3071): ╰→ com.example.ble_lib_leak.MainActivity instance
D/LeakCanary( 3071): ​     Leaking: YES (ObjectWatcher was watching this because com.example.ble_lib_leak.MainActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
D/LeakCanary( 3071): ​     key = c43c18c7-3f22-44c8-b4ae-d5dce58c5373
D/LeakCanary( 3071): ​     watchDurationMillis = 5198
D/LeakCanary( 3071): ​     retainedDurationMillis = 183
D/LeakCanary( 3071): ====================================
D/LeakCanary( 3071): 0 LIBRARY LEAKS
D/LeakCanary( 3071):
D/LeakCanary( 3071): A Library Leak is a leak caused by a known bug in 3rd party code that you do not have control over.
D/LeakCanary( 3071): See https://square.github.io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks
D/LeakCanary( 3071): ====================================
D/LeakCanary( 3071): METADATA
D/LeakCanary( 3071):
D/LeakCanary( 3071): Please include this in bug reports and Stack Overflow questions.
D/LeakCanary( 3071):
D/LeakCanary( 3071): Build.VERSION.SDK_INT: 29
D/LeakCanary( 3071): Build.MANUFACTURER: Sony
D/LeakCanary( 3071): LeakCanary version: 2.4
D/LeakCanary( 3071): App process name: com.example.ble_lib_leak
D/LeakCanary( 3071): Analysis duration: 4995 ms
D/LeakCanary( 3071): Heap dump file path: /data/user/0/com.example.ble_lib_leak/files/leakcanary/2020-09-30_22-35-03_352.hprof
D/LeakCanary( 3071): Heap dump timestamp: 1601498111563
D/LeakCanary( 3071): ====================================
W/ActivityThread( 3071): handleWindowVisibility: no activity for token android.os.BinderProxy@fc8ac1e

@b055man
Copy link
Author

b055man commented Oct 3, 2020

@dariuszseweryn @mikolak I run a similar test using the Flutter Reactive Ble package (https://pub.dev/packages/flutter_reactive_ble), which uses Polidea's rxandroidble library too (it interacts with it directly, not via the MultiplatformBleAdapter) - the difference is that they use the most-up-to-date version of the rxandroidble library, whereas the MultiAdapter still uses a 2-years old version (1.7.1). The RxStateObservable leak was fixed in version 1.10.0 dariuszseweryn/RxAndroidBle#575
Isn't this the cause then?

@b055man
Copy link
Author

b055man commented Oct 3, 2020

@dariuszseweryn another updated: as expected, using a newer version of the rxandroidble library solves this issue... but it's not that easy to migrate, as it now uses RxJava2.
However, thanks to @JamesMcIntosh PR here: dotintent/MultiPlatformBleAdapter#67 I managed to build FlutterBlePlugin using an updated version of MultiPlatformBleAdapter and the latest rxandroidble library. And guess what - the issue does not reproduce there..

So, guys @dariuszseweryn @mikolak - any chance to pursue that James's PR and moving MultiPlatformBleAdapter to RxJava2, to allow using recent versions of the rxandroidble library?

@b055man
Copy link
Author

b055man commented Oct 9, 2020

@mikolak @dariuszseweryn Guys, can you comment, please?

@mikolak
Copy link
Collaborator

mikolak commented Oct 9, 2020

Hi!

Sorry for the long silence, I'm completely swamped with work right now. I'd love to migrate it to new RxAndroidBLE, but I seem to recall there might be some issue with global error listeners (?). I hope to have some time from November. I'll consult it internally and try to get back to you, though I can't promise timely manner right now.

Thank you for investigating it so thoroughly!

@b055man
Copy link
Author

b055man commented Oct 9, 2020

@mikolak Thanks for providing the rough timeframe - I will bump the topic again sometime in Nov then, unless there are some updates before that time.

@b055man
Copy link
Author

b055man commented Dec 2, 2020

@mikolak @dariuszseweryn Hi guys, any updates on this one?

@mikolak
Copy link
Collaborator

mikolak commented Dec 11, 2020

@b055man I've just released 3.0.0-beta (https://github.com/Polidea/FlutterBleLib/releases/tag/v3.0.0-beta) with RxAndroidBle 2. Give it a go, lemme know if you encounter any issues. Let me know if everything works fine as well, as this will have to leave beta some day.

Closing for now.

@mikolak mikolak closed this as completed Dec 11, 2020
@b055man
Copy link
Author

b055man commented Dec 11, 2020

@mikolak Thanks. We'll give it a spin and I'll let you know the results.

@PiotrJozefow
Copy link

I'm still experiencing memory leak with version 3.0.0-beta.
When peripherial scan is running for about 3-5 minutes, calling peripherial.connect() causes sudden memory spike to up 2GB and app crashes.
Screenshot 2021-03-28 at 00 01 48

@JamesMcIntosh
Copy link
Contributor

JamesMcIntosh commented Mar 28, 2021

@PiotrJozefow I had a look last week and found a source of leaking, it's RxJava subscriptions in the MultiPlatformBleAdapter, will look at at PR when I get a moment.
See: #563 and dotintent/MultiPlatformBleAdapter#72

@PiotrJozefow
Copy link

@JamesMcIntosh I have no idea why but the memory leak I have occurs only when I have flutter animationController running on repeat at the time of peripherial scan. Thanks for fixing this and I'm really looking forward to your PR being merged 💪

@JamesMcIntosh
Copy link
Contributor

@PiotrJozefow are you repeatedly calling connect() or another method in the library, your animationController may be continuously refreshing the widget... add some breakpoints and see what happening.

@mikolak
Copy link
Collaborator

mikolak commented Apr 7, 2021

@bo55man @JamesMcIntosh have you encountered any issues using the beta?

@JamesMcIntosh
Copy link
Contributor

@mikolak I haven't had a chance to get back to it yet but I'm pretty sure it was affected by the same problem because of the way RxJava2 is used with subscriptions / observales.
dotintent/MultiPlatformBleAdapter#72

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants