17

I want my application to be connected to server though the mobile connection, yet allowing the device to go into sleep mode. I expect it to wake up when IP packates arrives.

How can this be done? How to receive "interrupts" from the Internet without draining battery?

Praful Bhatnagar
  • 7,425
  • 2
  • 36
  • 44
Vi.
  • 37,014
  • 18
  • 93
  • 148
  • I think a Service could solve your problem, but not without draining the battery. It could run on a background thread, which checks for packages in intervals. – Balázs Édes Nov 23 '12 at 19:24
  • I want my device to be online (e.g. receiving messages from XMPP) without significantly more battery usage. – Vi. Nov 23 '12 at 19:27

4 Answers4

24

When you are blocked on a read from a tcp stream the device can go into a deep sleep and when tcp traffic comes in it will briefly wakeup the device, as soon as a bit is read in you start a wakelock until you have received the whole transmission then release it.

Here is an example with web sockets, I've ran this app for over 12 hours in the background with no battery impact. https://github.com/schwiz/android-websocket-example

The client is here, the blocking read is in the start method. https://github.com/schwiz/android-websockets/blob/master/src/com/codebutler/android_websockets/HybiParser.java

Nathan Schwermann
  • 31,285
  • 16
  • 80
  • 91
  • 1
    `it will briefly wakeup the device` Is it reliable (including across NATs)? Is it in all Android versions? – Vi. May 17 '13 at 13:17
  • Yeah TCP connections work fine behind NATs. I'm not sure which versions of Android this all works in I've only tested with 4.2 However, Google's GCM services go all the way back to 2.2 and I assume they are doing something similar. I've checked with wireshark they too use TCP. – Nathan Schwermann May 18 '13 at 04:08
  • This is not a true. In your project you hold partial wake lock, so CPU remains active. – pepyakin Sep 20 '13 at 16:42
  • 4
    @kknot1 Only when there is data actually coming through the pipe, there is no wakelock in between communications. I left this programming running for over 12 hours and registered still less than 3 seconds of wakelock time after all of my keep-alive pings. This is precisely what I said and is in fact true. – Nathan Schwermann Sep 20 '13 at 17:50
  • I am trying to use this demo and it does not work like it should. The messages do not update in real time (only when reloading the app or the web page). Has anyone got it working? – Arthur Aug 06 '14 at 14:51
  • @Arthur I'm happy to try and trouble shoot with you. Probably easiest to open an issue on one of my github projects. – Nathan Schwermann Aug 06 '14 at 16:18
  • @schwiz we can try, but i'm new to python (by "new" i mean that i've looked into it only thanx to you socket example :D). Though i've had to change all `print "message"` to `print("message")` since in python 3 print is a function. It seems that there is a problem with `map` function in the python script. It simply does not send messages to all other sockets when a new list item arrives. – Arthur Aug 06 '14 at 16:43
  • @Arthur ahh Python3 could very likely be the issue, I have no clue if the tornado framework supports it or not. – Nathan Schwermann Aug 06 '14 at 16:54
  • 1
    @schwiz well everything is working except the `map` part. I've just replaced the `map` part with a `for` loop so everything is perfect now! Thanx! – Arthur Aug 06 '14 at 17:24
  • Does anyone know, why Google Cloud Messaging is sending heartbeat in such big intervals (up to 30 minutes)? Why they don't use same technique like in this example? This method is more reliable than GCM. – Arthur Aug 06 '14 at 18:10
  • Thanks @Arthur I assume GCM doesn't need as frequent of a heartbeat because it just plain has a lot of traffic. Handling pushes for all of the apps using it plus all of the google services. – Nathan Schwermann Aug 07 '14 at 03:03
  • just to update: this seems to be no longer possible in API levels starting 26 (Oreo) without using a foreground service. there're new restrictions for background services (https://developer.android.com/about/versions/oreo/background). – davee44 Jan 13 '20 at 08:25
12

I've been using long living TCP connections on Android without a wake lock for some years now.

My experience is that when data arrives on a TCP connection and the device is in deep sleep, it will be woken up for a short period of time at least. Waking up the device could take up to ~2 minutes sometimes, but it's usually done within a few seconds.

Now that the device is awake, the receiving process has some time too process the data. Now either the process is able to do so before the device is put back into deep sleep, or the device will be put into deep sleep suspending also the process. The important thing here is that the data is not lost, it remains in the memory and the process is able to resume the work processing the data the next time the device leaves deep sleep. Of course, this means that if the sender awaits an answer to his data, it may take some time, until he gets it.

You could take a wake lock as soon as your network library notifies you that a new message was received. But if you done, then make sure to handle the lock properly, i.e. ensure that it is released at some point and in every code path. I personally never experienced the need for a wake lock, the Android device was always long enough awake to process the request. But your millage may vary.

Flow
  • 23,572
  • 15
  • 99
  • 156
1

So this is very old but i ended up testing the behaviour @Flow described and just wanted to confirm that there seam to be arbitrary delays sometimes between the arrival of the data and the wakeup of the device.
I tested using a tcpClient implementation and an mqttimplementation. The idea was to see if there is an requirement of instantly getting the wakelock since this delay appeared in my mqtt implementation.
Test steup:

  • we have 2 services one running the tcpclient and one running the mqttclient in different apps
  • Both Services run on the same phone with the same permissions in the background.
  • The Server sends in both cases an "ping" message.
  • Our client implementation acquires a wakelock as soon as possible and reads the current Date.
    • for the tcpclient this is instantly
    • for the mqttclient the wakelock can only be acquired after the arriving data has been propagated through the networking libraries
  • we send back an response pong message including the read date
    • this send happens after wakelock release to see if this further delays the response time
  • the server logs incoming messages with the arrival and the read date

It appears that in both implementations there sometimes is an arbitrary delay to the call to our code. This makes it most likly that there is a delay to the wakeup of the device and not to the acquire of the wakelock.

  • this delay can be sometimes seen on all devices(tested on huaweip20light, HMD Global#Nokia 7.2, samsung#SM-N960F)
  • this delay seams more likly to happen on the HMD device higher api and victim of the stricter battery optimisations android established
flopfl
  • 21
  • 3
-2

Google Cloud Messaging might be what you are looking for:

http://developer.android.com/guide/google/gcm/index.html

cyroxx
  • 3,809
  • 3
  • 23
  • 35
  • I want take an existing application (e.g. Jabiru) and "magically" make it not drain battery (at expence of increased delay between incoming request and notification). – Vi. Nov 23 '12 at 19:39