A few weeks ago I wrote that a phone in your pocket is asleep, and there is nobody to wake it. BeeBEEP has no server, so no one can tap a sleeping phone on the shoulder when a message arrives. I described what I wanted to do about it, and it all sounded reasonable. On paper.
The Android version had been built and tested on the emulator, and the emulator has a kind flaw: it never really sleeps. It tells you the truth, but not all of it. So I took a real phone, a Samsung Galaxy A56, put it on a table, turned the screen off, and left it alone. What follows is what it told me.
The first half hour, straight into the bin
The plan was simple. A computer next to it sends the phone a message every five minutes and notes when each one arrives. Android itself keeps the accounts: how much battery BeeBEEP spends on the processor, the Wi-Fi, the Bluetooth, and on keeping the phone awake.
After thirty minutes I looked at the numbers. The phone had spent not a single minute in deep sleep. Not one. It was on its USB cable, and on its cable the A56 never really sleeps, whatever the software says. I had measured a phone that was pretending.
From then on, no cable. The debugging connection went over Wi-Fi and was closed for the whole run, so that not even my measuring could keep the phone awake. Half an hour, an hour, the phone untouched on the table.
Alive, but deaf
The first question was the one the earlier post had already answered on paper: the foreground service, the permanent notification that says BeeBEEP is running. Is it really needed? And what does it cost?
With the service on, linked to two computers, for an hour, twice: 24 messages out of 24, each delivered in less than a second. The price: 0.3 mAh an hour. Seven or eight mAh a day, 0.15% of the battery. In the same hour the phone's processor spent about 6 mAh on everything it did, and BeeBEEP's share was 1.4%.
Then I switched the service off. BeeBEEP stayed alive, kept in memory, and Android quietly kept the network away from it. Six messages sent, none arrived, for the whole half hour. Alive, but deaf.
The service stays, on by default. You can switch it off, and BeeBEEP tells you what that costs.
A sentence before Android's
There is one more way to stay awake: an exemption from battery optimisation, which Android grants if you ask. But the question it puts to you is its own, "Stop optimising battery usage?", with no context and no reason why. Now BeeBEEP speaks first. In its own words it explains that to get messages with the screen off it has to keep running, so please choose Allow. Then Android asks. Once, at the first start, never again.
Does it matter? I forced Doze, Android's deepest sleep, by hand. With the service running, a message arrived in 0.125 seconds without the exemption and in 0.136 with it, each with its notification and its sound. So with the service, no. Without the service, it is everything: with the exemption all six messages arrived, without it none.
A phone that says nothing
This was the hard part, and I had not seen it coming.
A computer already linked to the phone keeps it reachable on its own. Every ten seconds or so it sends a small message to keep the link alive, the message wakes the phone, the phone answers. They keep each other company.
But a computer that starts while the phone is asleep, and has never met it, must first hear it. And a sleeping phone says nothing. In half an hour with nobody linked, it was awake for 54 seconds in all. I started a computer alone next to it and waited. Twenty minutes, and it never found it.
This is what having no server really means. In a messenger with a server, someone always knows who is where. Here nobody makes the introductions. Two devices on the same table, and they do not know about each other.
Twelve seconds too many
The first answer was a periodic wake. Every ten minutes an Android alarm wakes BeeBEEP, which keeps the processor for twelve seconds, announces itself and checks its links.
It worked: a new computer found the sleeping phone in 61 seconds, at a wake. But the bill had more than doubled, 0.72 mAh an hour against 0.32. And Android did not care much for my ten minutes: the alarms came four times in the hour, from 12.6 to 17.5 minutes apart. Under Doze, an alarm that is not exact is spread as the system pleases.
Where had the battery gone? I went through the accounts. Nearly all of it went into holding the processor, and each wake held its full twelve seconds, though its work needs about four. One wake cost about 0.12 mAh, and almost all of that was waiting.
So the wake learned to leave as soon as its work is done, with the twelve seconds kept only as a limit. I measured again, in the same way. The four wakes held the processor for 2.0, 6.2, 2.1 and 2.0 seconds: 0.068 mAh for all four, against 0.47. The price of a wake fell from 0.12 mAh to 0.017.
The work had never been the cost. The waiting was.
In that same run the wake showed me what it buys. At minute 21 a computer lost the phone, for a reason I could not see. The next wake came 3 minutes and 51 seconds later, announced the phone, and the link was back at once. The day before, with no wake, the same kind of loss had lasted ten and a half minutes.
So the wake stays, on by default. I will not pretend it always makes things faster. Once, in an hour without wakes, a new computer found the phone in 60 seconds, by pure chance. In the last run a newcomer linked after eight and a half minutes, on an announcement the phone sent between two wakes. What the wake buys is not speed. It is a limit: a new computer finds a sleeping phone within one interval, ten to eighteen minutes under Doze, instead of perhaps never, and a lost link comes back at the next wake. All of this is about Wi-Fi. Bluetooth has nothing to do with it.
The Bluetooth that would not sleep
The same accounts held a surprise. A line I had not expected: Bluetooth, on the air, scanning, for the whole hour the phone slept. 0.12 mAh, 30% of everything BeeBEEP spent.
When the screen went off while BeeBEEP was open, Android reported two changes a few milliseconds apart: "suspended", then "inactive". BeeBEEP took "inactive" to mean "still in front", and kept listening for devices nearby, on a phone lying alone on a table. Now only "active" brings BeeBEEP back in front. One more long run on the phone will be the final check.
No test would have found it. Only a real phone, measured, shows a thing like that.
The small lies of sleep
Left alone, the phone told me other things too.
With the screen off, the Wi-Fi stops listening to the computers' announcements, 12 to 41 seconds later, while the processor is still awake. The Wi-Fi filters them by itself.
Timers stop in deep sleep. BeeBEEP's own little message to keep a link alive, due every 5 to 7 seconds, went out about once every 46. The link lived on the computer's messages, whose arrival wakes the phone.
My favourite: a sleep that looked like someone changing the clock. BeeBEEP keeps an eye on the time, in case someone moves it, and in half an hour it complained 152 times. I added up the gaps it had seen: 1565 seconds, exactly the 26 minutes the phone had spent in deep sleep. The clock it compared against stops when the phone sleeps, and the wall clock does not. BeeBEEP had been watching the phone dream and calling it fraud. Fixed.
A reinstalled phone and a computer that started in the same second called each other at the same time; the radio lost both calls, and nobody called again. Fixed: afterwards, five restarts next to a starting computer linked by themselves, in half a second to three.
And behind the lock screen nothing starts. Launched while the phone was locked, BeeBEEP existed but did not run a single line until the face unlock, 2 minutes and 16 seconds later.
Bluetooth, on real radios
The earlier post ended with Bluetooth: a way to find each other with no internet and no server, within the walls of an office. Then, for the first time, it ran between real devices.
A computer recognised the phone as a contact nearby over Bluetooth alone, with nobody pressing search. From the moment it dialed the phone to the moment it showed it nearby: 4.85 seconds. On paper I had guessed a few hundred milliseconds; the radio's connection alone took three seconds. Still, it worked.
Once. The next eleven tries all timed out. When the last connection closes, Qt's Android code closes the phone's Bluetooth server, and BeeBEEP, restarting, had opened a new one, empty. The phone went on advertising BeeBEEP with nothing behind it, like a shop with its sign lit and nobody inside. The cause was found the same day: now a fresh server is built after every disconnection.
After every connection the phone also advertises from a new random address: BeeBEEP restarts its advertisement, and Android gives each start a fresh address. It would be nice to say that this is what keeps you from being followed, but it is not the whole story. The small signal behind it, 16 bytes, stays the same for fifteen minutes, so within those fifteen minutes a scanner could tell that the addresses belong to one phone. What protects you is the signal itself: every fifteen minutes it changes, and to a stranger it never meant anything.
And the lesson of the day came from the computer. The Linux one could not advertise at all. A device may answer a scan with a second short packet, the scan response, but Qt's Bluetooth code on Linux cannot send one. So it squeezed both of BeeBEEP's identifiers, the service and the signal, into a single advertisement: 40 bytes, where a classic one allows 31. One computer's adapter refused it. A newer one accepted it as an "extended" advertisement, which Android's scan does not even listen to. It would have failed in silence, the worst way to fail. On the simulated radio of the tests, everything had passed.
The answer: where the system cannot send a scan response, the signal does not go on the air, and the phone recognises that computer by its address, as it already does with an iPhone. It costs one short read every fifteen minutes, and nothing in privacy, because such a computer already advertises from a fixed address.
Three tenths of a milliampere-hour
A server would have spared me most of this. It knocks, the phone wakes, end of story. Without one, BeeBEEP has to be awake enough to be found and asleep enough not to be noticed, and the line between the two is drawn in fractions of a milliampere-hour.
Now I know where that line is. In the background, linked, with the screen off, BeeBEEP costs about 0.3 mAh an hour, 0.15% of the battery a day, and messages arrive in less than a second. A wake costs 0.017.
A phone in your pocket is asleep, I wrote. It still is. But now it hears you.
