How to manually have ACRA send pending reports (offline use) - android

We're in this situation where our clients use our mobile application offline 95% of the time. At the end of their work day, when they get back to the office, they synchronize all data with our servers while they have network connectivity.
We have ACRA set up with the AcraHttpSender plugin to attempt sending us the crash reports directly, however this usually fails because they're using the application offline and ACRA stores the reports instead.
From what I understand the pending reports will only be sent by ACRA when the application is restarted, through ACRA.init. The problem is the users have no reason to restart the application at the end of their work day (while they have network connectivity). I have to stress that the users are complete tech illiterates, our clients made that clear to us.
So, we would really need to be able to tell ACRA to send us any pending crash reports it has during the short time network connectivity is available. Without user interaction of any kind. I was thinking maybe in the onCreate function of our main activity.
However I've been looking at documentation and other people asking the same question for a while and haven't found anything obvious. Is this possible?
EDIT: This is the current working code with the suggestion made by #F43nd1r and #CommonsWare. It wasn't working for me with 5.4.0, but with 5.5.1 it is.
Gradle
def acraVersion = '5.5.1'
implementation "ch.acra:acra-core-ktx:$acraVersion"
implementation "ch.acra:acra-http:$acraVersion"
implementation "ch.acra:acra-advanced-scheduler:$acraVersion"
implementation "ch.acra:acra-toast:$acraVersion"
Initialization
initAcra {
setBuildConfigClass(BuildConfig::class.java)
setReportFormat(StringFormat.JSON)
plugin<ToastConfigurationBuilder> {
setResText(R.string.acra_crash_text)
setLength(Toast.LENGTH_LONG)
setEnabled(true)
}
plugin<HttpSenderConfigurationBuilder> {
setUri("${BuildConfig.protocol}://${BuildConfig.host}/${BuildConfig.codemrc}/acra")
setHttpMethod(HttpSender.Method.POST)
setBasicAuthLogin("acra")
setBasicAuthPassword("******")
setEnabled(true)
}
plugin<SchedulerConfigurationBuilder> {
setRequiresNetworkType(JobInfo.NETWORK_TYPE_ANY)
setRestartAfterCrash(true)
setResReportSendSuccessToast(R.string.acra_report_sent_text)
setEnabled(true)
}
}
// Turn this on to obtain more messages in the log to debug ACRA
ACRA.DEV_LOGGING = BuildConfig.DEBUG

As #CommonsWare stated in the comments, AdvancedSenderScheduler is the way to go.
Example usage:
implementation "ch.acra:acra-advanced-scheduler:5.5.1"
#AcraScheduler(requiresNetworkType = JobInfo.NETWORK_TYPE_UNMETERED,
requiresBatteryNotLow = true)
In case you're not satisfied with AdvancedSenderScheduler options, you could also register your own SenderScheduler, but that should rarely be necessary.

Related

firebase sendUnsentReports() sends exceptions only after restart

I want to send info about user non-fatal exceptions through recordException() method, but default crashlytics implementation sends them only after app is restarted (which is quite a strange behaviour o_O)
I tried to disable automatic reports collection through setCrashlyticsCollectionEnabled(false) method and send them manually through sendUnsentReports(), but, alas, firebase continues to send them only after the app is restarted.
Has anybody solved that kind of a problem and how?
Yes, that’s expected. Logged exceptions are not sent immediately when they are recorded, otherwise there would be pull requests at random intervals which would use up a lot of bandwidth and battery.
They are batched and sent either on startup or at crash time, and when you call sendUnsentReports, all cached reports are sent at that time, but it doesn’t send anything from the current session.

Android BLE BluetoothGatt.writeDescriptor() return sometimes false

I'm trying to write BLE Android app. I found that sometimes when I call
BluetoothGatt.writeDescriptor() it returns false.
I have not found in documentation any note of limitation to this function. But ppl on stack overflow says that I need to wait for BluetoothGattCallback.onDescriptorWrite() before I try to write another descriptor.
Here is one reply saying that BLE is busy with writeDescriptor() and can not do other write.
Here is another thread saying that you can not call twice writeCharacteristic().
My questions are
is it really true?
is there really missing some internal android API buffer for serializing BLE requests and every developer has to do it on it's own?
Is it true for different functions? For example when I call writeDescriptor() I understand I can not call second time writeDescriptor() before I receive onDescriptorWrite(). But do I have to wait for onDescriptorWrite() when I want to call writeCharacteristic()?
Also if there is inter-function dependency then what else function have this limitation (namely: readCharacteristic(), readDescriptor(), requestMtu()...)?
And additionally is there interdependency between BluetoothGattServer and BluetoothGatt. So for example when I call BluetoothGattServer.notifyCharacteristicChanged() shall I wait forBluetoothGattServerCallback.onNotificationSent before I can call BluetoothGatt.writeDescriptor() or BluetoothGatt.writeCharacteristic()? (BTW praise for google documentation onNotificationSent() is by luck documented properly. Doc says:
When multiple notifications are to be sent, an application must wait
for this callback to be received before sending additional
notifications.
Lastly having all this questions - I feel that Android BLE API is under-documented. Or am I wrong and there is documented somewhere what are allowed methods calling sequences? If yes can you please point me to such documentation? If not is there some channel we can open issue with google and ask them to add to documentation something? I mean it may not be much text - some function like onNotificationSent() is arleady properly documented. They just need to copy this sentence to other functions.
The documentation lacks information. However you can read the source code to find out the rules, which (currently) are the following:
For each BluetoothGatt object, you can only have one outstanding request at a time, including requestMtu, readCharacteristic, writeCharacteristic, readDescriptor, writeDescriptor and executeReliableWrite. So if you issue a read request you need to wait for the read response before you issue a write request. While they implemented the code that returns false if there is an ongoing operation in BluetoothGatt.java, they forgot to do this for requestMtu, so if you have multiple requests at a time where requestMtu is one of them, you will get random errors sooner or later (in the latest versions at the time of this post).
So yes, every developer has to manually serialize the requests. Note that the Bluetooth stack actually has a queue of requests, but it is limited to only one request per client (i.e. BluetoothGatt object). So if two apps on the same phone talk to the same device simultaneously you will never get "busy" errors. The only exception is if you use Write Without Response for which the current data flow implementation is quite buggy (see https://issuetracker.google.com/issues/37121017 which Google seems to have ignored).
You can send notifications at the same time as you write a characteristic, since the server and client roles are separated.
Regarding updating the documentation, you can always try to file an issue at https://issuetracker.google.com (but I get the feeling nobody reads that), or, since Android is open source, send a pull request to https://android-review.googlesource.com/ which updates the Javadoc from which the documentation is generated.

Proper error handling when sending an XMPP push notification using go-gcm?

I'm using https://github.com/google/go-gcm to send push notifications from our Go backend to Android devices. Recently, these push notifications started failing because the call to SendXmpp() was returning with the following error:
write tcp <IP>:<port>-><IP>:<port>: write: connection timed out
Restarting the Go process that called SendXmpp() makes this error go away, and push notifications start working again. But of course, restarting the Go process isn't ideal. Is there something I can do explicitly to handle this kind of error? For instance, should I close the current XmppClient and retry sending the message, so that the retry instantiates a new XmppClient and opens a new connection?
I would recommend using or implementing a (exponential) backoff. There are a number of options on GitHub here; https://github.com/search?utf8=%E2%9C%93&q=go+backoff though that's surely not a comprehensive list and it's not terribly difficult to implement.
The basic idea is you pass the function you'd like to call in to the back off function which calls it until it hits a max failures limit or it succeeds. Between each failure the amount of time waited is increased. If you're hammering a server, causing it to return errors, a method like this will typically solve your problems and make your application more reliable.
Additionally, I'd recommending looking for one that has an abort feature. This can be implemented fairly easily in Go by passing a channel into the backoff function (with the function you want to call). Then if your app needs to stop you can signal on the abort channel so that the back off isn't sitting there with like a 300 second wait.
Even if this doesn't resolve your specific problem it will generally have a positive effect on your apps reliability and 3rd party API's you interact with (don't want to DOS your partners).

How to send ping using Eclipse Paho MQTT client?

We've just started building our own push notification system (due to client's requirement) for Android and found Eclipse Paho (http://www.eclipse.org/paho/). Needless to say, this project is really exciting.
The problem with Android is, if the CPU is in sleep state, the MQTT client may not get the chance to send ping at its set interval. The workaround is using AlarmManager to wake it up and get the job done. The Android documentation says:
The Alarm Manager holds a CPU wake lock as long as the alarm
receiver's onReceive() method is executing. This guarantees that the
phone will not sleep until you have finished handling the broadcast.
Once onReceive() returns, the Alarm Manager releases this wake lock.
This means that the phone will in some cases sleep as soon as your
onReceive() method completes.
http://developer.android.com/reference/android/app/AlarmManager.html
I need to be sure that I could send the ping command within that onReceive() method while the CPU has PARTIAL_WAKE_LOCK, so I was searching a way to manually sending ping to server but it seems the client doesn't expose any such method. Am I missing something? Or, what is the workaround here except publishing my own "ping message"? I want to avoid that because of:
Larger overhead
We'll ensure that Android clients are subscriber only, may be with Mosquitto's ACL. They will not be allowed to publish messages.
I've been doing some work with MQTT on Android and I've experienced exactly the same issue.
As Dale says, the old version of the MQTT client used to have an explicit ping() method, but unfortunately this is now hidden away.
The simplest approach, and the one I use, is to explicitly publish a 1 byte message to a particular topic, to serve as the keepalive. I don't think this should add much to the overhead of your application and, while I'm not familiar with Mosquitto's ACL, I assume you could have every client use the same 'keepalive' topic and just provide write access to all. This shouldn't affect security as long as no-one can read from the topic.
An alternative approach would be to have the server send the client(s) a 'keepalive' message at QoS 1 or 2 (pub/sub through a single topic to all for efficiency) as, due to the QoS flows, this will involve the client sending a message back to the server under the covers; which will serve as the keepalive. This has the advantage of keeping your clients as subscriber only; however it's incompatible with 'clean session = false' (as you would have large amounts of messages queued up for delivery to clients who are offline for a while - needlessly affecting performance on reconnect).
Unfortunately these are the only two workarounds that I can currently think of.
Also, as a brief aside, I've experienced a number of issues using the MqttDefaultFilePersistence on Android, so you might want to be aware of this. In particular to do with file locking and problems when re-instantiating the client. To get around this I've created an implementation of MqttClientPersistence built on top of an SQLite database and this is much more robust; you might want to do the same.
I came across this issue when writing MQTT apps for Android a year or so ago. I've written about it at some length at http://dalelane.co.uk/blog/?p=1599 but in short, yes - I saw the same problem that you describe where if the CPU is asleep when the MQTT client should send it's ping, then the ping never gets sent.
The difference is that I was using a different MQTT client library to you (this was before the days of Paho), and the client library that I used did have a ping() method that I could call. (The full source for my implementation is at that link, and it does solve this problem).
Can you not extend the implementation of the Paho client library to include the PING command? I assume it should be a reasonably small modification.
There is a way to modify the paho code and make a ping at any time. If we use publishing topic to keep alive, we have to send at least 7 or 8 bytes to server. Yes, 8 bytes is still not big data. But the heartbeat of MQTT is only 2bytes. We have lost the best advantage of MQTT.
Look deeply into the paho code, I modify it and write a public method named nnnn() in MQTTClient. This method could send MqttPingReq to th server. the implemetation can be found here...https://github.com/chinesejie/paho-for-android
my solution:
(1) modify: ClientComms comms; from protected to public (in package org.eclipse.paho.client.mqttv3)
public class MqttAsyncClient implements IMqttAsyncClient { // DestinationProvider {
//...
public ClientComms comms; // Add by Ben for pingreq*
//...
}
(2) define new class: (derived from MqttClient)
public class MqttClient2 extends MqttClient {
public MqttClient2(String serverURI, String clientId, MqttClientPersistence persistence) throws MqttException {
super(serverURI, clientId, persistence);
}
public void pingreq() throws MqttException {
MqttDeliveryToken token = new MqttDeliveryToken(getClientId());
MqttPingReq pingMsg = new MqttPingReq();
aClient.comms.sendNoWait(pingMsg, token);
}
}
(3) anywhere, you can:
MqttClient2 mClient = new MqttClient2(url, mDeviceId, mDataStore);
mClient.pingreq();
hope this can be helpfull for you.

Android Force Close Uncatchable Unreportable

I've released my second game project on the Android Market this week, and immediately had multiple 1-star reports due to force closes. I tested it on many handsets and many emulators with zero issues. I'm completely at a loss for how to proceed and looking for advice.
I use Thread.setDefaultUncaughtExceptionHandler to intercept and report uncaught exceptions, then close gracefully. The people reporting force closes aren't getting to any of that, even though it is the first thing set in the application's main task constructor, and everything is wrapped in try/catches throughout. They are also reporting that there is no "Send Report" option in the force close popup (providing the Developer Console error reports), so I have absolutely no way of knowing what the problem is.
Uses Android 2.0, with android:minSdkVersion="5". Only Permission required is INTERNET.
(on Android market as 'Fortunes of War FREE' if you want to test)
I'm a bit surprised about the missing "Send report" button. What API level did you build the game with? I usually build the level with your minimum API level to make sure you're not using any API calls beyond that, but then switch back to the highest API level so you can use functionality like "install to SD".
I'm sure there's at least one user who wrote you a mail. Can you ask them to install LogCollector and mail you the log?
Btw, in general, I wouldn't use Thread.setDefaultUncaughtExceptionHandler so there IS the option to send a report. (It's ominously missing in your case, but normally, it should be there.)
Btw btw, the exception handler applies to the current thread. If you have an OpenGL app, maybe the crash happens in the GL thread?
I'm not sure if I understood you correctly, but as far as I know Android only shows that report dialog if you use its default UncaughtExceptionHandler.
Try this:
In your UncaughtExceptionHander's constructor, call Thread.getDefaultUncaughtExceptionHandler and save the returned object in a variable (let's call it defaultHandler). In your Handler's uncaughtException() do the things you want to do, and then call defaultHandler.uncaughtException() afterwards.
Maybe something you should know:
In my experience, your Context isn't functional anymore at uncaughtException(). So, you can't send broadcasts, etc anymore.
By the way, if you really wrapped everything in try/catch, that could be the reason why error reporting doesn't work as expected? :P
Good luck
Tom
Perhaps the force closes are caused by stalls, rather than exceptions. Users may not notice the difference. This kind of problem can occur more often if users have CPU hogging services running at the same time as your application, which explains why you're not seeing the issue in your testing.
Permission Internet sounds a lot like you try to transfer data from the net, which is very fast in your local LAN, but all of a sudden becomes slow (and time consuming) when people try this over their GSM connections.
If you then do the data transfer in the UI thread, this one is blocked and the system detects the block - but then this should end up in a "Did not respond" -- but then I've seen one user report an error with in the market on my app that was such a slow down cause.

Categories

Resources