I want an Android service, which is listening for data (I have tried TCP and UDP) to wake up the service/phone when data arrives.
Currently the phone stays asleep when IP data arrives and that data is lost. Is this normal for Android? I see sleeps of 2+ hours several times a day, and 7+ hour sleeps when I am asleep.
Does GCM provided a solution which wakes up a service/phone when a message arrives.
I need messages to be displayed within a few seconds of them being sent from the server.
Can this only be achieved by keeping the CPU running all day long? Is there no interrupt from the GSM modem on the arrival of data?
As I understand it, if you have an outstanding socket connection over mobile data to a server, that socket connection is maintained while in sleep mode, and incoming packets will wake up the phone out of sleep mode (briefly) to deliver the data.
The same is not true of WiFi (and presumably not for hardwired Ethernet, either). You would need to hold a WakeLock and a WifiLock.
Does GCM provided a solution which wakes up a service/phone when a message arrives.
Yes, but...
I need messages to be displayed within a few seconds of them being sent from the server.
First, GCM has no service-level guarantee. I am not aware of any solution that does, including anything that you might roll yourself (e.g., MQTT).
Second, you have no idea if the device is capable of receiving any such messages (GCM or otherwise), as the device may be turned off, in airplane mode, etc.
Related
I bought myself a smartwatch that has Android KitKat running.
I have connected it to my HTC m9 smartphone using Bluetooth.
I have created an application that is running on both smartwatch(client mode) and smartphone(server mode).
The applications are talking each other over a Bluetooth Socket connection.
When I get a phone call on my phone, I am sending a Bluetooth notification over the Bluetooth socket to the watch and make it vibrate.
All is good as long as the watch's CPU is up and running.
When the watch goes to sleep, and I get a phone call on the smartphone, the notification is not processed by the watch because watch's CPU is sleeping.
Using a partial lock on the watch does the thing but it consumes the battery to fast.
I don't need a partial lock on the phone, because when the phone receives a call, the phone is "magically" awaken, so my application's service is able to send the notification.
I also can't use AlarmManager on the watch, because I need the watch to wake up when I get a bluetooth socket notification, not on regular intervals.
A WakefullRecevier is also not solving the problem because my watch needs to wake up first so that the WakefullReceiver puts the power lock (or have I got this wrong ?!) and runs its code.
So the question is: How does the phone wake up on incoming call? Or on SMS received? It is a hardware thing..an interrupt?
Is there any way of waking up the watch when a bluetooth message is received?
Thank you
For the past few days I've been playing around with the watch making different tests.
I am not answering the original question but since nobody else answered the question I will just write down my own conclusions which are good enough for my application and maybe help others with similar problems.
1. When the paired watch is in Bluetooth range of the phone, a power lock is not needed on the watch.
Any messages sent by the phone are received by the watch.
If the watch stays idle for some time, the 1st Bluetooth message sent by the phone is received with about 1 second delay. Probably Android watch goes into some kind of low power mode but is able run my code when Bluetooth message is received. Of course Bluetooth messages are received almost immediately by the watch while the watch is not idle.
2. Best way to find out if a Bluetooth socket is still connected, is to write into it.
Socket read is a blocking call but it does not throw IOException when watch goes out of Bluetooth range. I wasn't able to find a read timeout property I can change.
So I am just writing a byte into the socket every 60 seconds to detect if socket is not connected anymore. Battery impact is minimum while socket down detection timing is acceptable.
3. When the paired watch is NOT in Bluetooth range of the phone anymore, Bluetooth socket re-connect strategy is required.
Using a partial lock in this case does not seem like a good approach since it keeps the CPU awake. Also trying to re-connect to often to the phone kills the battery.
The re-connect strategy is based on application needs.
I ended up using WakefulBroadcastReceiver and AlarmManager to make a socket connect attempt with a given period.
4. Every now and then, when the watch goes out of Bluetooth range, then comes back into range, then again and again the Bluetooth socket seems to go in some kind of 'zombie' state. Sometimes the socket.connect call just blocks without succeeding or throwing error, some other times the socket.connectcall does not throw error given the impression that connection has been established, but a subsequent write always throws IOException.
Whenever I encounter these kinds of situations I just stop/start Bluetooth adapter which seems to solve the problem.
5. Pay attention to stop/start the Bluetooth adapter. During Bluetooth restart attempt Android can put the CPU to sleep. I wasn't expecting this behavior but it really happens. So if you want to do this as fast as possible without any delay, make sure the application acquires a PARTIAL_WAKE_LOCK during the re-start attempt. Of course don't forget to release the lock as soon as possible.
When a device is using the mobile Internet (3G, 4G), it connects to Internet every 30 minutes. This can be seen with emails coming in a bunch instead 1 by 1 like when a device is on wi-fi (among other things).
How come that push-messages for chat apps (hangouts, whatsapp, viber,...) come immediately?
I actually noticed that only Skype messages do not come immediately when I am on the mobile data connection. Others come instantly.
When a device is using the mobile Internet (3G, 4G), it connects to Internet every 30 minutes. This can be seen with emails coming in a bunch instead 1 by 1 like when a device is on wi-fi (among other things).
That just means that those apps happen to be pulling down data every 30 minutes, whether via AlarmManager or JobScheduler or SyncManager or whatever. They could just as easily set their AlarmManager polling period to be 27 minutes, or 2.7 minutes, or 27 days.
How come that push-messages for chat apps (hangouts, whatsapp, viber,...) come immediately?
On a Play Services ecosystem device, either they are using GCM (which maintains an open socket connection), or they are using their own GCM-workalike (which maintains an open socket connection for however long they can keep their service running), or they are using something like AlarmManager with a small polling period (which is really bad for the battery, but that doesn't stop people).
On a Kindle Fire, they might be using Amazon equivalents of GCM, etc.
What makes mobile data interesting is that incoming packets on an open socket connection will wake up the CPU. From there, the apps for which those packets are destined can grab a WakeLock to be able to have time to process those packets. WiFi sockets are usually torn down around the time when the CPU goes into sleep mode, in part because usually the WiFi radio itself usually goes into a sleep mode around the same time, to conserve battery.
I actually noticed that only Skype messages do not come immediately when I am on the mobile data connection.
Skype might not use GCM for competitive reasons. I'm a bit surprised that they aren't using their own workaround GCM-like service (e.g., MQTT-based).
I've setup an Android app with GCM support, and have a little test app to send a msg to the app.
When I run the App in the emulator, I can see (via logging msgs) that it registers with GCM and gets a Token.
Then when I put the token in my test app and have it send a msg, the result shows that 1 msg was sent, 0 failed, and 0 had ID changes.
Sometimes the msg shows up almost immediately, sometimes it takes 20 minutes.
On Friday, my 2 test msgs took 15 and 20 minutes.
The first 2 I sent this morning were immediately, the next one hasn't shown up yet - it's only been 10 minutes...
Is there anything I can do to make the delivery times consistently fast? A random 20 minute delay will be pretty much an unacceptable condition.
We had the same problem, but it varied from network-to-network. We think it was the home hub router (a Virgin Super Hub) dropping the connection after five minutes of inactivity. You can confirm by sending an empty GCM message every two minutes to keep the connection alive.
Here is a more in-depth explanation of what we did: https://groups.google.com/d/msg/android-gcm/Y33c9ib54jY/YxnCkaPRHRQJ
You cannot guarantee fast delivery because GCM to device connectivity may be poor as CommonsWare has pointed out. There are however, two possible delays in the delivery train: 1) GCM connecting to the phone (as mentioned previously) and 2) The delay in the message actually being sent out from the GCM server. If you set the 'time_to_live' parameter to 0 seconds in your sending application, then you can at least test where the delay is occurring.
A value of 0 seconds means that the message will be sent immediately and if delivery is unsuccessful, the message will be discarded on the GCM server. It is not a practical value for real life use, but will enable you to find out which part of the delivery train is causing the delay.
This is indeed caused by unrealistic heartbeat intervals in Google Cloud Messaging.
This is possibly the most frustrating bug in GCM. GCM works by maintaining an idle socket connection from an Android device to Google’s servers. This is great because it barely consumes battery power (contrary to polling), and it allows the device to be woken up instantly when a message arrives. To make sure that the connection remains active, Android will send a heartbeat every 28 minutes on mobile connection and every 15 minutes on WiFi. If the heartbeat failed, the connection has been terminated, and GCM will re-establish it and attempt to retrieve any pending push notifications. The higher the heartbeat interval, the less battery consumed and the less times the device has to be woken up from sleep.
However, this comes at a great price: the longer the heartbeat interval, the longer it takes to identify a broken socket connection. Google has not tested these intervals in real-life situations thoroughly enough before deploying GCM. The problem with these intervals is caused by network routers and mobile carriers, who disconnect idle socket connections after a few minutes of inactivity. Usually, this is more common with cheap home routers, whose manufacturers decided on a maximum lifespan of an idle socket connection, and terminate it to save resources. These routers can only handle a finite number of concurrent connections, and so this measure is taken to prevent overload. This results in terminated GCM sockets, and when the time comes to deliver a GCM message, it does not reach the device. The device will only realize that the connection has been broken when it’s time to send a heartbeat, 0 – 28 minutes later, rendering the push notification useless in some situations (when the message is time-critical, for example). In my experience, most cheap routers terminate idle connections after about 5 – 10 minutes of inactivity.
I wrote an entire post about this and other GCM issues:
http://eladnava.com/google-cloud-messaging-extremely-unreliable/
An Alternative to Google Cloud Messaging
Pushy (https://pushy.me/) is a standalone push notification gateway, completely independent of GCM. It maintains its own background socket connection, just like GCM, to receive push notifications. The underlying protocol is MQTT, an extremely light-weight pub/sub protocol, utilizing very little network bandwidth and battery.
A huge advantage of Pushy is that the code for sending a push notification (from the server), and registering the device for push notifications, is actually interchangeable between GCM and Pushy. This makes it super easy to switch to Pushy after implementing GCM and having to ditch it for its instability.
(Full disclosure: I founded Pushy for my own projects and realized many apps would benefit from such a service)
GCM is reportedly having a pretty severe problem with keep-alive heartbeat not being so reliable. Therefore, since it's only dispatched once every 15 minutes (over 3G) or 28 minutes (over Wifi), if for some reason the server connection is dropped, it may not be restored for several long minutes.
These type of shenanigans prompted developing a solution that does not rely on a 3rd-party network to deliver massively-scalable and reliable push notifications to offline (backgrounded) Android apps.
https://help.pubnub.com/entries/21720011-Can-my-Android-App-Receive-Messages-While-Inactive
This matter is important to me.
I have set up this code inside a one second timer Handler to send out a GCM message every 2 minutes. The hope is that it will keep things alive
if ((mOneSecondTick %120) == 0){
// q 1 minute check when we got last call....
long lDiff = System.currentTimeMillis() - GCMlastCall;
if (PushAndroidActivity.GCMAvailable){
Log.d("pushAndroidActivity",String.format("(mOneSecondTick %d",lDiff));
if (lDiff > 122 * 1000){ // more than a minute
Intent intent = new Intent(StayInTouch.this,PushAndroidActivity.class);
2startActivity(intent);
}else{ // every 2 minutes send out a gcm message...
asyncWebCall(String.format(AgeingLib.GCMTICKLE,androidid),0);
return; // only if it sends a tickle and all is well...
}
}else{
Log.d("pushAndroidActivity",String.format("(mOneSecondTick mod60 no GCM on this device"));
}
}
GCMlastCall is the last time a message was received, so we can tell if gcm stopped.
Been working for a couple of days now seems OK
I need to keep a TCP connection established indefinitely (as far as possible). Is not an own server so we cannot change the way it works. This server needs some kind on ping each minute to know that the connection is alive. If the server do not receive the ping after some minutes (less than five), the connection and the session is closed. In this way i need to maintain a TCP connection with the server and be able to send pings at the periods specified.
At the moment i have an Android service with the flag "ongoing" so Android should not kill it (at least by normal procedures). The android service seems to run fine and the pings are sent periodically. However when the service is running on a mobile phone (not emulator) and it gets idle, android seems to freeze the service while the CPU is sleeping, so the TimerTask sending pings stop working and the connection goes down.
I have tried to lock the phone from going to sleep with a partial wake lock and it solves the problem but the phone consumes too battery, what is unfeasible.
I noticed that the AlarmManager may help on this task, so i want to schedule an alarm to update the running service and then send the ping. This will let the CPU going to sleep and also the ping being sent. But schedule an alarm each minute may be also so battery consuming or not?
I have not tested this approach at the moment, but is feasible? is there a better way to keep this kind of TCP connection?. How android services like Gmail solves this kind of issues?
I need to keep a TCP connection established indefinitely with a server.
Why?
For starters, it is technically impossible. Users will switch between networks (e.g., was on WiFi, failed over to 3G), users will leave areas where they have Internet coverage, users will turn on airplane mode, etc.
At the moment i have an Android service with the flag "on_course" so Android should not kill it.
There is no such concept as "on_course" in Android. Android services can and will be killed by users (task killer, force-stop in Manage Services) or by the OS. And, since this will be an everlasting services, your users will kill your service if they do not understand what value it is continuously delivering.
I have tried to lock the phone from going to sleep with a partial wake lock and it solves the problem but the phone consumes too battery, what is unfeasible.
Correct.
I noticed that the AlarmManager may help on this task, so i want to schedule an alarm to update the running service and then send the ping. This will let the CPU going to sleep and also the ping being sent. I have not tested this approach at the moment, but is feasible?
Sure. You will still consume too much battery, IMHO. Please allow your user to control your polling period, with a wide range of options (e.g., 10 minutes, 30 minutes, one hour, never).
How android services like Gmail solves this kind of issues?
They use C2DM, which is part of the OS and took a lot of engineering to get right. There was a presentation on it at the 2010 Google I|O conference -- the video should be on YouTube. Note that they do the heartbeat ping every 30 minutes IIRC, and they optimize for the case where the device is on 3G (to allow the WiFi radio to turn off after inactivity).
If your objective of your permanent connection is to implement a push-style communications channel, please consider using C2DM.
You can wake phone from idle with partial wake lock right before you execute ping and after you do it release wakelock. It will scientifically reduce battery consumption and it will do the job. Also, try to increase ping time as long as you can.
5 Minutes is a little short for the ping time, can you configure the server to hold the connection longer? 30 minute ping or higher would be ideal. Here is an example of an application that holds a background tcp connection and will wake up the device from a deep sleep on incoming tcp traffic. https://github.com/schwiz/android-websocket-example
According to this Android C2DM keeps a socket alive with a heartbeat mechanism, making it able to receive push messages. This made me hope I could deliver messages to sleeping phones with an active wifi connection.
I've made an implementation setting the "delay_while_idle" to '0'. The message is delivered if my phones' screen is powered off, but not if the phone goes to sleep (tested with intervals 20mins, 1-6 hours).
I have acquired a partial cpu lock + a full wifi lock just in case.
Have I simply made something fundamentally wrong or did I misunderstand the C2DM push functionality?
Can I send messages to sleeping phones or not?
Using alarmmanager instead of wakelocks could keep your phone alive just enough. See this implementation. Will test a variant of this.