eclipse / paho.mqtt.android

MQTT Android
Other
2.93k stars 883 forks source link

MqttConnection throws exception(Failed to ensure directory) when trying to connect #185

Open rafaelekol opened 7 years ago

rafaelekol commented 7 years ago

I am using MQTT to get and publish messages to Server. On most phones MQTT connect and disconnect is working, but on Phone: LG LFino with Android Kitkat 4.4.2, and HTC Desire 310 with Android JellyBean 4.2.2 I got exception when I try to immediately connect after disconnect.

I use MqttAndroidClient in my local service. Here is my code.

public class MqttAppService extends Service {

@Override
    public void onCreate() {
        super.onCreate();
MqttAndroidClient mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), serverUri, deviceId);
        mqttAndroidClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
               setSocketState(CONNECTED);
                if (reconnect) {
                    Log.d(TAG, "Reconnected to : " + serverURI);
                } else {
                    Log.d(TAG, "Connected to: " + serverURI);
                }
            }

            @Override
            public void connectionLost(Throwable cause) {
                Log.d(TAG, "The Connection was lost.");
               setSocketState(DISCONNECTED);
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                try {
                    SocketDispatcher.getInstance().dispatch(new String(message.getPayload()));
                } catch (Exception e) {
                    Log.e(TAG, "messageArrived: ", e);
                }
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
            }
        });

        mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setKeepAliveInterval(5);
        mqttConnectOptions.setAutomaticReconnect(true);
        mqttConnectOptions.setCleanSession(true);
        mqttConnectOptions.setUserName(username);
        mqttConnectOptions.setPassword(accessToken.toCharArray());
}

private void connectToMqtt() {
        try {
            mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
                    disconnectedBufferOptions.setBufferEnabled(true);
                    disconnectedBufferOptions.setBufferSize(100);
                    disconnectedBufferOptions.setPersistBuffer(false);
                    disconnectedBufferOptions.setDeleteOldestMessages(false);
                    mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.e(TAG, "Failed to connect  exception: ", exception);
                }
            });

        } catch (MqttException ex) {
            Log.e(TAG, "connectToMqtt: ", ex);
            ex.printStackTrace();
        }
    }
}

Log:

    ContextImpl: Failed to ensure directory: /storage/external_SD/Android/data/com.sample.app/files/MqttConnection
    02-14 11:50:24.762 
E/MqttAppService: Failed to connect  exception: 
     MqttException (0)
  at org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence.restoreBackups(MqttDefaultFilePersistence.java:273)
  at org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence.open(MqttDefaultFilePersistence.java:120)
  at org.eclipse.paho.client.mqttv3.internal.ConnectActionListener.connect(ConnectActionListener.java:175)
  at org.eclipse.paho.client.mqttv3.MqttAsyncClient.connect(MqttAsyncClient.java:592)
  at org.eclipse.paho.android.service.MqttConnection.connect(MqttConnection.java:295)
  at org.eclipse.paho.android.service.MqttService.connect(MqttService.java:329)
  at org.eclipse.paho.android.service.MqttAndroidClient.doConnect(MqttAndroidClient.java:467)
  at org.eclipse.paho.android.service.MqttAndroidClient.access$200(MqttAndroidClient.java:76)
  at org.eclipse.paho.android.service.MqttAndroidClient$1.run(MqttAndroidClient.java:435)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
  at java.lang.Thread.run(Thread.java:841)

After more testing found out that phones where I can see this Exception in common has low available memory (About 200MB free memory).

rafaelekol commented 7 years ago

I removed DisconnectedBufferOptions and faulty devices seems to connect and disconnect fine now.

jpwsutton commented 7 years ago

Looks like your application did not have permission within Android to read/write to the sdcard. You might need to change your application manifest file.

Something like <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

rafaelekol commented 7 years ago

I already have that permission in Manifest.

rafaelekol commented 7 years ago

Even though I disabled DisconnectedBufferOptions I still get exception on HTC device, whenever I change WiFi connection, I get this exception. The big issue is that, after that moment I can't connect to socket anymore, since client.connect() is always throwing this error afterwards. I observe this error on this device: HTC Desire 310 with Android JellyBean 4.2.2

onFailure: 
MqttException (0)
at org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence.restoreBackups(MqttDefaultFilePersistence.java:276)
at org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence.open(MqttDefaultFilePersistence.java:126)
at org.eclipse.paho.client.mqttv3.MqttAsyncClient.<init>(MqttAsyncClient.java:391)
at org.eclipse.paho.android.service.MqttConnection.connect(MqttConnection.java:289)
at org.eclipse.paho.android.service.MqttService.connect(MqttService.java:329)
at org.eclipse.paho.android.service.MqttAndroidClient.doConnect(MqttAndroidClient.java:467)
at org.eclipse.paho.android.service.MqttAndroidClient.access$200(MqttAndroidClient.java:76)
at org.eclipse.paho.android.service.MqttAndroidClient$1.run(MqttAndroidClient.java:435)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:838)
GregoryHo commented 7 years ago

I got the same situation as refaeleko, some devices are working correctly, but the device "Lenovo YT3-X90F" with 5.1

First connection :

W/ContextImpl: Failed to ensure directory: /storage/sdcard1/Android/data/com.sample.app/files/MqttConnection
D/AlarmPingSender: Register alarmreceiver to MqttServiceMqttService.pingSender.cht_ffdYOGA5DCE9841_MainClient
D/AlarmPingSender: Schedule next alarm at 1493976855031
D/AlarmPingSender: Alarm scheule using setExact, delay: 10000
E/Connection: cht_ffdYOGA5DCE9841_MainClient connection complete, isReconnect = false

After few seconds, connection lost and auto reconnect:

D/AlarmPingSender: Sending Ping at:1493977577617
D/AlarmPingSender: Schedule next alarm at 1493977577852
D/AlarmPingSender: Alarm scheule using setExact, delay: 231
D/AlarmPingSender: Unregister alarmreceiver to MqttServicecht_ffdYOGA5DCE9841_MainClient
D/AlarmPingSender: Schedule next alarm at 1493977582708
D/AlarmPingSender: Alarm scheule using setExact, delay: 100
E/Connection: cht_ffdYOGA5DCE9841_MainClient connection lost, throwable = 連線遺失 (32109) - java.io.EOFException
D/AlarmPingSender: Register alarmreceiver to MqttServiceMqttService.pingSender.cht_ffdYOGA5DCE9841_MainClient
D/AlarmPingSender: Schedule next alarm at 1493977594199
D/AlarmPingSender: Alarm scheule using setExact, delay: 10000
E/Connection: cht_ffdYOGA5DCE9841_MainClient connection complete, isReconnect = true
D/AlarmPingSender: Sending Ping at:1493977594201
D/AlarmPingSender: Schedule next alarm at 1493977604204
D/AlarmPingSender: Alarm scheule using setExact, delay: 10000
D/AlarmPingSender: Success. Release lock(MqttService.client.cht_ffdYOGA5DCE9841_MainClient):1493977594415

Here is my disconnect code :

@override
public void onPause() {
  if (status == CONNECTED || status == CONNECTING) {
      try {
        client.disconnect();
        setStatus(LEAVE);
      } catch (MqttException e) {
        e.printStackTrace();
      } catch (IllegalStateException e) {
        e.printStackTrace();
      }
    }
}

Disconnect :

D/AlarmPingSender: Success. Release lock(MqttService.client.cht_ffdYOGA5DCE9841_MainClient):1493977605601
D/AlarmPingSender: Unregister alarmreceiver to MqttServicecht_ffdYOGA5DCE9841_MainClient
E/Connection: cht_ffdYOGA5DCE9841_MainClient connection lost, throwable = null

Connect again when resume :

W/ContextImpl: Failed to ensure directory: /storage/sdcard1/Android/data/com.sample.app/files/MqttConnection
E/ActionListener: Connect to mqtt server failure, MqttException (0)

My connection options:

mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setUserName(userName);
mqttConnectOptions.setPassword(mqttPassword);
mqttConnectOptions.setConnectionTimeout(30);
mqttConnectOptions.setKeepAliveInterval(10);
mqttConnectOptions.setAutomaticReconnect(true);
mqttConnectOptions.setCleanSession(false);

Current library:

compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

Also i already have the "android.permission.WRITE_EXTERNAL_STORAGE" in Manifest. Thanks.

jianglijs commented 7 years ago

who know the answer,i have the same problem.

jianglijs commented 7 years ago

I find the answer: MqttDefaultFilePersistence filePersistence = new MqttDefaultFilePersistence(getDir("mqtt", MODE_PRIVATE).getAbsolutePath()); MqttAndroidClient mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), MQTT_BROKER_HOST, clientId,filePersistence); when in Android ,we should pass our own filePersistence in.The exactly answer still don,t know

algrid commented 6 years ago

Another option is to use memory persistence (if you can allow for messages to be lost when the app is killed):

mqttAndroidClient = new MqttAndroidClient(context, serverUri, clientId,
                new MemoryPersistence(), MqttAndroidClient.Ack.AUTO_ACK);
sukhwinder-kaur commented 6 years ago

HI . I am using this type url mqtt://mqtt.go.th:1883 but with this i can't get make connection between my android app and mqtt server. But when i am trying it with this tcp://mqtt.go.th:1883 it make connection . what happened with mqtt:// ? I need this type url connection. please give me solution . Thank you.