Arnt Gulbrandsen
About meAbout this blog

Network problem analysis for Android apps

Most apps tell the user to check this and that when there's a network problem, any network problem. The web browsers I've seen offer the same evasive blah-blah for any problem except a failing TLS certificate.

I have an app that's mine alone, though. It shares my values and its behaviour is guided by my pet peeves, including being annoyed by messages that just say can't reach server. So for it I wrote a class to analyse a network problem and offer a less generic message.

My analysis is quick and will offer a diagnosis after at most 2.5 seconds. My reasoning here is that when something takes a little longer than usually, there may or may not be a problem, and it's reasonable to start analysis while continuing to try. After a couple of seconds more, there very likely is a real problem, and the app should offer the user a decent explanation. That gives a couple of seconds from when a problem appears likely until the explanation must be ready.

It's cheap, in particular it doesn't cause a lot of network traffic. It sends and receives packets, but not so many as to slow down existing up/downloads. This is because I want to start the analysis before I'm certain that there is a problem.

It's more liberal about sending packets on the local WLAN than about packets across the internet.

It performs all analysis locally. The local device is the only one that is known to be reachable when there's a network problem, so that's where I do all the work.

This implies that if you want to access a URL containing sensitive or personal information, that URL stays in your app, and you comply with all current and future data protection rules.

It also doesn't try to access the URL, because who knows what might happen? It simply trusts your assertion that there's a problem, and finds the most likely type of problem. If nothing is wrong, then the analysis won't make sense.

It recognises the main types of problems and I accept that it may be wrong and definitely won't spot the exact problem. This is a good-versus-best issue. I can deliver a good analysis and promise to have the result ready within 2.5s, but the best possible analysis might take longer. I decided for speed and low cost, and decided that every message to the user, in every language, must convey probability rather than certainty.

Here's what it does, at the time of writing: If a resource isn't reachable from a device, then that's either

  • because the device is offline,
  • because the device has IPv4 or -6 and the resource requires the other,
  • because the device's upstream router is unreachable,
  • because that router cannot reach the general internet,
  • because the device's local DNS resolver doesn't do its job,
  • because your connection works but is too flaky,
  • because the resource isn't reachable from the general internet,
  • because of a problem at the site where the resource is hosted,
  • or for some indecipherable reason.
Eight plus uh, not sure. My code does some quick checks to find out which kind looks most likely.

Usage: Include the code in your app's build.gradle using compile(''), import no.priv​.gulbrandsen​.anpa​.NetworkProblemAnalysis;, and at the appropriate spot in your code you start analysis using NetworkProblemAnalysis​.forHost(string)​.timeout(millis)​.onConclusion((problem) -> {…})​.start(); A small example app shows exactly how to do it.

The host may be a DNS name or an IPv4/6 address, timeout() is optional, and if you don't call start() nothing happens. The result is usually available long before the timeout (even instantly, if the problem is that the device is in airplane mode). start() returns quickly; the work is done in background threads. You can save a reference to the analysis object just before you start() and call cancel() at any time. The callback from onConclusion() occurs in a thread of its own, and its argument has this enum type.

If there is no problem and you don't cancel() the analysis, your lambda will be called when the timeout is reached, and the argument will not make any sense.

How does it work? If you tell it the problem relates to www.example.com, it will do DNS lookups for www.example.com, example.com, and .com, as well as run a few ping commands with the -c, -i and -t options. Classifying the problem is simple given that data.

Have fun. Serve the users. Send me mail if you have questions or comments. Or raise an issue, or submit a PR.

Update, many years later: I wrote the above on my desktop while I also wrote the code on my then laptop. Later that day I saw a flash, a fuse blew and the laptop was thoroughly dead.

I thought I'd rewrite that code but somehow that didn't happen. The whole thing was surrounded by bad karma. Until now, with Claude's help. Claude used about a dozen files where I used three (two classes and one enum), but there's no denying it, the result is better. I told Claude what to do, we measured and discussed, Claude wrote code, we tested, measured and discussed again, after a few iterations the result's good. We are in a new phase of software development.

I reread both No Silver Bullet and The Mythical Man-Month recently, when Claude changed my world. They're both perceptive, both hold up well in this new age IMO, and I don't think Claude is a 10× silver bullet, but Claude does seem to be a 2× change overall, and sometimes more, as in this case. 2× on average is fantastic. Have fun. Serve the users.