OmemoManager does not responding sometimes

Hi,

I are using Smack 4.2.1-beta2-SNAPSHOT and getting error with omemo manager initialization. I am initializing OmemoManager after xmpp authentication in a asynchronous task. Sometimes, it ends with an exception when there is a fresh installation and regenerating a new device identity.

Check if id 602523018 is available...
 I/OmemoStore: Regenerating with deviceId 602523018...
W/art: Suspending all threads took: 7.272ms
 E/FileBasedOmemoStore: Could not write preKey with id 36: java.io.FileNotFoundException: /storage/emulated/0/.LiveCare/Media/Omemo/OMEMO_Store/86@xmpp2.livecare.ca/602523018/preKeys/36: open failed: EACCES (Permission denied)
    java.io.FileNotFoundException: /storage/emulated/0/.LiveCare/Media/Omemo/OMEMO_Store/86@xmpp2.livecare.ca/602523018/preKeys/36: open failed: EACCES (Permission denied)
        at libcore.io.IoBridge.open(IoBridge.java:456)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
        at org.jivesoftware.smackx.omemo.FileBasedOmemoStore.writeBytes(FileBasedOmemoStore.java:641)
        at org.jivesoftware.smackx.omemo.FileBasedOmemoStore.storeOmemoPreKey(FileBasedOmemoStore.java:264)
        at org.jivesoftware.smackx.omemo.OmemoStore.storeOmemoPreKeys(OmemoStore.java:564)
        at org.jivesoftware.smackx.omemo.OmemoStore.regenerate(OmemoStore.java:108)
        at org.jivesoftware.smackx.omemo.OmemoService.regenerate(OmemoService.java:272)
        at org.jivesoftware.smackx.omemo.OmemoService.initialize(OmemoService.java:221)
        at org.jivesoftware.smackx.omemo.OmemoManager.initialize(OmemoManager.java:209)
        at app.com.livecare.connect.chat.ConnectXMPP.setupOMEMO(ConnectXMPP.java:4740)
        at app.com.livecare.connect.chat.ConnectXMPP.access$6700(ConnectXMPP.java:154)
        at app.com.livecare.connect.chat.ConnectXMPP$SetUpOMEMOTask.doInBackground(ConnectXMPP.java:4697)
        at app.com.livecare.connect.chat.ConnectXMPP$SetUpOMEMOTask.doInBackground(ConnectXMPP.java:4693)
        at android.os.AsyncTask$2.call(AsyncTask.java:292)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        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:818)
     Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
        at libcore.io.Posix.open(Native Method)
        at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
        at libcore.io.IoBridge.open(IoBridge.java:442)
             at java.io.FileOutputStream.<init>(FileOutputStream.java:87) 
             at java.io.FileOutputStream.<init>(FileOutputStream.java:72) 
             at org.jivesoftware.smackx.omemo.FileBasedOmemoStore.writeBytes(FileBasedOmemoStore.java:641) 
             at org.jivesoftware.smackx.omemo.FileBasedOmemoStore.storeOmemoPreKey(FileBasedOmemoStore.java:264) 
             at org.jivesoftware.smackx.omemo.OmemoStore.storeOmemoPreKeys(OmemoStore.java:564) 
             at org.jivesoftware.smackx.omemo.OmemoStore.regenerate(OmemoStore.java:108) 
             at org.jivesoftware.smackx.omemo.OmemoService.regenerate(OmemoService.java:272) 
             at org.jivesoftware.smackx.omemo.OmemoService.initialize(OmemoService.java:221) 
             at org.jivesoftware.smackx.omemo.OmemoManager.initialize(OmemoManager.java:209) 
             at app.com.livecare.connect.chat.ConnectXMPP.setupOMEMO(ConnectXMPP.java:4740) 
             at app.com.livecare.connect.chat.ConnectXMPP.access$6700(ConnectXMPP.java:154) 
             at app.com.livecare.connect.chat.ConnectXMPP$SetUpOMEMOTask.doInBackground(ConnectXMPP.java:4697) 
             at app.com.livecare.connect.chat.ConnectXMPP$SetUpOMEMOTask.doInBackground(ConnectXMPP.java:4693) 
             at android.os.AsyncTask$2.call(AsyncTask.java:292) 
             at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
                                                       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:818) 
D/SMACK: SENT (0): <iq to='86@xmpp2.livecare.ca' id='b7sK8-29' type='get'><query xmlns='http://jabber.org/protocol/disco#info' node='eu.siacs.conversations.axolotl.devicelist'></query></iq>
D/SMACK: RECV (0): <iq xml:lang='en' to='86@xmpp2.livecare.ca/2442' from='86@xmpp2.livecare.ca' type='result' id='b7sK8-29'><query node='eu.siacs.conversations.axolotl.devicelist' xmlns='http://jabber.org/protocol/disco#info'><identity type='pep' category='pubsub'/><identity type='leaf' category='pubsub'/><identity type='registered' category='account'/><feature var='http://jabber.org/protocol/pubsub'/><feature var='http://jabber.org/protocol/rsm'/><feature var='http://jabber.org/protocol/pubsub#create-nodes'/><feature var='http://jabber.org/protocol/pubsub#auto-create'/><feature var='http://jabber.org/protocol/pubsub#auto-subscribe'/><feature var='http://jabber.org/protocol/pubsub#delete-nodes'/><feature var='http://jabber.org/protocol/pubsub#delete-items'/><feature var='http://jabber.org/protocol/pubsub#filtered-notifications'/><feature var='http://jabber.org/protocol/pubsub#modify-affiliations'/><feature var='http://jabber.org/protocol/pubsub#outcast-affiliation'/><feature var='http://jabber.org/protocol/pubsub#persistent-items'/><feature var='http://jabber.org/protocol/pubsub#publish'/><feature var='http://jabber.org/protocol/pubsub#purge-nodes'/><feature var='http://jabber.org/protocol/pubsub#retract-items'/><feature var='http://jabber.org/protocol/pubsub#retrieve-affiliations'/><feature var='http://jabber.org/protocol/pubsub#retrieve-items'/><feature var='http://jabber.org/protocol/pubsub#retrieve-subscriptions'/><feature var='http://jabber.org/protocol/pubsub#subscribe'/></query></iq>
D/SMACK: RECV (0): <r xmlns='urn:xmpp:sm:3'/>
D/SMACK: SENT (0): <a xmlns='urn:xmpp:sm:3' h='12'/>
D/SMACK: SENT (0): <iq to='86@xmpp2.livecare.ca' id='b7sK8-31' type='get'><pubsub xmlns='http://jabber.org/protocol/pubsub'><items node='eu.siacs.conversations.axolotl.devicelist'/></pubsub></iq>
D/SMACK: RECV (0): <iq xml:lang='en' to='86@xmpp2.livecare.ca/2442' from='86@xmpp2.livecare.ca' type='result' id='b7sK8-31'><pubsub xmlns='http://jabber.org/protocol/pubsub'><set xmlns='http://jabber.org/protocol/rsm'><index>0</index><count>1</count><first index='0'>creation@001506:520278:365175</first><last>creation@001506:520278:365175</last></set><items node='eu.siacs.conversations.axolotl.devicelist'><item id='5E27F056576F1'><list xmlns='eu.siacs.conversations.axolotl'><device id='1801292086'/></list></item></items></pubsub></iq>
D/SMACK: RECV (0): <r xmlns='urn:xmpp:sm:3'/>
D/SMACK: SENT (0): <a xmlns='urn:xmpp:sm:3' h='13'/>
D/SMACK: SENT (0): <iq to='86@xmpp2.livecare.ca' id='b7sK8-33' type='set'><pubsub xmlns='http://jabber.org/protocol/pubsub'><publish node='eu.siacs.conversations.axolotl.devicelist'><item><list xmlns='eu.siacs.conversations.axolotl'><device id='602523018'/><device id='1801292086'/></list></item></publish></pubsub></iq>
D/SMACK: RECV (0): <iq xml:lang='en' to='86@xmpp2.livecare.ca/2442' from='86@xmpp2.livecare.ca' type='result' id='b7sK8-33'><pubsub xmlns='http://jabber.org/protocol/pubsub'><publish node='eu.siacs.conversations.axolotl.devicelist'><item id='5E28CB0673DB6'/></publish></pubsub></iq>
D/SMACK: RECV (0): <r xmlns='urn:xmpp:sm:3'/>
D/SMACK: SENT (0): <a xmlns='urn:xmpp:sm:3' h='14'/>

As shown above, after FileNotFoundException error, it has only published new device list without publishing new bundle for that device list. For this operation in asynchronous task, overridden method onPostExecute() has not been called. The CPU usage for this operation goes high.

Here is my code for initializing OmemoManger in a asynchronous task.


private class SetUpOMEMOTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            setupOMEMO(0);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            Log.d(SECURE_HEALTH_TAG, "onPostExecute : SetUpOMEMOTask");
}
}


private void setupOMEMO(int retryCount) {

        if (retryCount < CONNECTION_RETRY_THRESHOLD) {

            Log.d(SECURE_HEALTH_TAG, retryCount > 0 ? "Retrying setting up OMEMO" : "Setting up OMEMO");
            if (!SignalOmemoService.isServiceRegistered()) {

                SignalOmemoService.acknowledgeLicense();
                try {
                    SignalOmemoService.setup();
                } catch (InvalidKeyException | CorruptedOmemoKeyException | InterruptedException | SmackException | NoSuchProviderException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | UnsupportedEncodingException | InvalidAlgorithmParameterException | NoSuchPaddingException | XMPPException.XMPPErrorException e) {
                    e.printStackTrace();
                }
                OmemoConfiguration.setFileBasedOmemoStoreDefaultPath(new File(OMEMO_STORE));
            }

            try {

                mOmemoManager = OmemoManager.getInstanceFor(connection);
                mOmemoManager.addOmemoMessageListener(new MyOmemoMessageListener());
                //mOmemoManager.addOmemoMucMessageListener(new MyOmemoMUCMessageListener());

                if (isAuthenticated()) {

                    mOmemoManager.initialize();
                    mOmemoManager.purgeDevices();
                    mOmemoManagerSetup = true;

                }

            } catch (Exception e) {
                e.printStackTrace();

                if (!(e instanceof SmackException.NoResponseException)) {
                    shutDownOmemo();
                    setupOMEMO(++retryCount);
                }
            }

        }

    }

And second thing, i want only one device active at one time so i am purging old devices. For purging operation with smack omemo, it will publish new device id and bundle. So its like publishing each for two times, first when initializing omemo manager and second time during purging devices. So i think, if required, it should directly purge all other devices during omemo manager initialization itself.

Thanks
Vishnu Prajapati

https://github.com/igniterealtime/Smack/pull/177 adds an asynchronous method to initialize OmemoManager :slight_smile: