hivemq / hivemq-mqtt-client

HiveMQ MQTT Client is an MQTT 5.0 and MQTT 3.1.1 compatible and feature-rich high-performance Java client library with different API flavours and backpressure support
https://hivemq.github.io/hivemq-mqtt-client/
Apache License 2.0
872 stars 161 forks source link

Android | ANR while creating & conencting MQTT3 client #606

Open pravingws opened 12 months ago

pravingws commented 12 months ago

🐛 Bug Report

🔬 How To Reproduce

Steps to reproduce the behavior:

  1. Not sure on how to reproduce but it is this ANR is reported by many users.

Code sample

`private fun createMqttClient() { logMqtt("WSConnMgr :: createMqttClient() >> $clientIdentifier")

    if (mqttCredsHandler.isValidData()) {
        val websocketConfig = MqttWebSocketConfig.builder().serverPath(MQTT_SERVER_PATH).build()

        // refer: https://stackoverflow.com/questions/71495372/hivemq-java-library-fails-to-automatically-reconnect-to-broker
        mqtt3Client = Mqtt3Client
                .builder()
                .identifier(clientIdentifier)  // The unique identifier of the MQTT client
                .serverHost(mqttCredsHandler.getMqttUrl()) // The host name or IP address of the MQTT server
                .serverPort(mqttCredsHandler.getMqttPortNumber()) // The address (host + port) of the MQTT server
                .webSocketConfig(websocketConfig) //WebSocket transport configuration
                .sslWithDefaultConfig() // Secure transport configuration (SSL/TLS)
                // .automaticReconnectWithDefaultConfig()  // Default -startInitDelay is 1s and maxDelay is 120s
                .automaticReconnect() // Lifecycle configuration - Automatic reconnect configuration
                .initialDelay(1, TimeUnit.SECONDS) // Sets the initial delay the client will wait before it tries to reconnect
                .maxDelay(2, TimeUnit.SECONDS) // Sets the maximum delay the client will wait before it tries to reconnect.
                .applyAutomaticReconnect() // Lifecycle configuration - Automatic reconnect configuration
                .simpleAuth()
                .username(mqttCredsHandler.getMqtttUserName())
                .password(mqttCredsHandler.getMqttPasswordByteArray())
                .applySimpleAuth()
                .addConnectedListener { context ->
                    logMqtt("WSConnMgr ::CONNECT SUCCESS  onConnected() >>: context = $context")
                    handleListenerQueue()
                    reAttemptCounter = 0
                }
                .addDisconnectedListener { context ->
                    logMqtt("WSConnMgr :: mqttDisconnectConnectionListener callback: " +
                            "\n D-Listeners: " + wsListenersList.size +
                            "\n D-Message: " + context.cause.message +
                            "\n D-source: " + context.source.toString() +
                            "\n D-State: " + context.clientConfig.state.toString() +
                            "\n D-Cause: " + context.cause, "e")
                    handleMqttDisconnect(context)
                }.buildAsync()

        try {
            val connAckFuture = mqtt3Client!!
                    .connectWith()
                    .keepAlive(MQTT_KEEP_ALIVE_SEC)
                    .cleanSession(false)
                    .send()

            logMqtt("WSConnMgr ::connAckFuture >>: context = ${connAckFuture.get().returnCode}")
        } catch (e: Exception) {
            logMqtt("WSConnMgr ::connAckFuture >>: Error: " + e.localizedMessage, "e")
        }

    } else {
        logMqtt("WSConnMgr ::connAckFuture FAILURE. MQTT CREDS NOT FOUND. NOT ATTEMPTING TO CONNECT !!", "e")
    }
}`

Environment

Where are you running/using this client?

Hardware or Device? ANDROID OS version 11 & above

What version of this client are you using? MQTT3 & dependency version 1.3.1

JVM version?

Operating System? ANDROID

Which MQTT protocol version is being used? MQTT3

Which MQTT broker (name and version)? hive and 1.3.1

Screenshots - NA

📈 Expected behavior

📎 Additional context - Stacktrace

ANR stacktrace from Playconsole app vitals: at jdk.internal.misc.Unsafe.park (Native method) at java.util.concurrent.locks.LockSupport.park (LockSupport.java:211) at java9.util.concurrent.CompletableFuture$Signaller.block (CompletableFuture.java:1861) at java9.util.concurrent.ForkJoinPool.managedBlock (ForkJoinPool.java:3231) at java9.util.concurrent.CompletableFuture.waitingGet (CompletableFuture.java:1888) at java9.util.concurrent.CompletableFuture.get (CompletableFuture.java:2063) at com.wrkspot.employee.common.mqtt.WSMqttConnectionManager.createMqttClient (WSMqttConnectionManager.java:136) at com.wrkspot.employee.common.mqtt.WSMqttConnectionManager.initiateMqttConnection (WSMqttConnectionManager.java:70) at com.wrkspot.employee.backgroundservice.WrkspotMqttService.onCreate (WrkspotMqttService.java:107) at android.app.ActivityThread.handleCreateService (ActivityThread.java:4641) at android.app.ActivityThread.access$1800 (ActivityThread.java:262) at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2174) at android.os.Handler.dispatchMessage (Handler.java:111) at android.os.Looper.loopOnce (Looper.java:238) at android.os.Looper.loop (Looper.java:357) at android.app.ActivityThread.main (ActivityThread.java:8111) at java.lang.reflect.Method.invoke (Native method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1026)

Plain text logs stacktrace (1).log

yuriisurzhykov commented 4 months ago

@pravingws I'm not sure if it helps you to find out the solution, but Android throws ANR (application not responding) when application doesn't response within 5 seconds on user input (touches), that is, if the main UI thread is taken by operation that prevents the UI from rendering new frames. This can happen only if you run some operation that takes more than 5 seconds on the UI thread after you did something that triggers UI to be rerendered, or updated, or response to the user.

So what could you do: