I have an app thats designed mostly to run in the background. The only notable things that go on is that there is pretty much a MediaRecorder running 24/7 for the microphone, and that an alarm manager is set to run some very simple (non-cpu intensive) code every 5-10 minutes (based upon user settings).
Battery usage details on my phone report the app is using about 100 mA per hour, compared to apps like Instagram and Snapchat which average about 25-30 mA per hour. Consumption level reports its responsible for 25% of my phones battery brain. And finally Power Analysis shows "CPU time used (background): 33 min, 48s, GPS running time <1s, Wi-Fi running time <1s, Kept system on for 1 min 24s."
Considering the app is designed to run 24/7 in the background, im trying to reduce power usage as much as possible. I figure apps like Instagram and Snapchat are constantly checking for new messages and would therefore be more power intensive than an app that only runs once every 5-10 minutes, but clearly thats not the case.
I do run several other threads in the background, but they're mostly used for timing and should be closed after no more than 5 seconds. Are they're any recommendations as to how to reduce the power usage?
Most likely MediaRecorder is the culprit as it keeps media path powered on. Most well-written app are not constantly checking for new messages and events and use push notifications instead
Also, it is recommended to use JobScheduler instead of alarm manager
Related
I have been following https://developer.android.com/guide/topics/connectivity/wifi-scan guide in order to create a Wi-Fi scanner. I am using a foreground service with a handler to call wifiMananger.startScan(); every 30 seconds (I tried with 15 minutes).
Everything works great for about 2 hours then suddenly WifiManager.EXTRA_RESULTS_UPDATED boolean returns false and the wifiManager.getScanResults() are not getting updated. Then as soon as the phone is plugged in it starts sending results again. (No, it is not low on battery)
I have battery optimization turned off. I have all of the required permissions allowed. Locations is turned on with Wi-Fi scanning enabled. The device I'm testing on is a Samsung S7 Edge running Android 8. So I know it's not the new OS. (I also tested with a Nokia 5.1 running Android 10 with pretty much the same results).
Does anyone know why this is happening or has anyone encountered this issue before?
Thanks in advance.
Updated: In case of your problem, since you are using exactly 30 seconds due to some problem there might be more than 4 time in a 2 minutes period, make it like 35 seconds and test the result.
Original Answer: From this WifiManager startScan throttled in P Beta (Developer Preview 2) :
"Call Limitations - Throttling
We are further limiting the number of scans apps can request to improve network performance and improve battery life.
The WifiManager.startScan() usage is limited to:
Each foreground app is restricted to 4 scans every 2 minutes.
All background apps combined are restricted to one scan every 30 minutes."
It is said that this restriction is due to the battery drain, so it is normal to remove the restriction while charging.
Read more about throttling in official documentation.
This is because Android OS enters the infamous "Doze mode". I recommend you to look through the official documentation/explanation.
Unfortunately, there is no way around this. It will also affect any kind of a foreground service and pause it for longer periods. Doze mode will only trigger if the screen is locked and the device is not plugged in.
I encountered the same issue on my project and we implemented a periodic check. If the screen is locked and device not plugged in for a longer period of time, we show a notification asking the user to either plug the device in or open the app so the service could keep working. The implementation is a bit lengthy, but if it is what you decide to go with, I can update the answer with some of the code (using the AlarmManager within a BroadcastReceiver to achieve this).
In my app, I make an internet connection every 10 minutes via the AlarmManager APIs to download data.
I would like the app to make at least 6 attempts to connect, one every 30 seconds if there a problem with the network connectivity.
Is it possible?
It isn't possible to do that on a modern Android device where by modern I mean Android 6 or greater.
6: Doze [Doze that comes on roughly an hour after the screen is turned OFF]
7: Doze++ [Doze that comes on shortly after the screen is turned OFF]
8: Background restrictions [Inability to run services that are not in the foreground]
Google's recommended way of doing syncing like this is to use a JobScheduler or Firebase Cloud Messaging if you have luxury of doing a server implementation.
With out knowing all the requirements, it sounds like the app may need to use the AlarmManager if you're determined to sync more frequently than the JobScheduler allows.
There is only 1 API in the AlarmManager that is guaranteed to be called reliably once every 30 seconds and that is setAlarmClock. However, it cannot be used to start a service. It can only send a user-facing alarm and a PendingIntent that will be executed when the user clicks on the alarm.
The two APis most likely to be useful to you are setAndAllowWhileIdle and setExactAndAllowWhileIdle. Both these APIs can be used to start a service. The alarms will execute frequently when the screen is ON or the device is charging. However, when the device is in the power saving mode called Doze they can only execute during Doze maintenance windows. This means they can still run at least once every 9 minutes during most normal doze windows.
Now apps targeting Android 8 must address another new restriction, they have to call startServiceInForeground. A foreground service sets an on going notification like your media player for example. So it makes the user more aware that the service is running and usually gives them an option to stop it.
Now foreground services are 'exempt' from doze, a few things to be aware of:
When a foreground service is active it prevents the entire device from dozing which greatly increases the battery usage
In Android 6 foreground services will be dozed anyway unless they are in a separate process due to a framework defect
I've heard that some devices will eventually kill a foreground service if you leave it running for an extraordinary amount of time
But the real answer to your question is: "Don't do it". Does the app really need to use that much battery and data? Running every 30 seconds is extraordinary and even if was possible it would make the app a "bad citizen" on the phone...
In my Android application I need to send a message to the server (basically a ping) once a minute when a certain feature is activated. The feature may be activated for 2-3 hours, so it's important that the ping is sent continuously and in a timely fashion.
To achieve this I am currently using AsyncTasks (for sending the request), launched once a minute via a foreground Service, which is scheduled with alarmManagers' setExactAndAllowWhileIdle. The foreground service does have a partial wakelock too!
Unfortunately it looks like Marshmallow's doze mode ends up swallowing the alarms at some random point. This happens EVERY TIME and at arbitrary points. Sometimes the app sends pings for 2 hours without problems, sometimes only for 30 minutes, before they don't go off anymore (and then restarting 10-15 minutes later).
What can I do to get the ping sent continuously? It is incredibly important for the app. The only other alternative I can see is that I use the GCM to send high-priority messages every 5 minutes or so to keep it alive, but I that would be a terrible hack.
Ask the user to add your app to the battery optimization whitelist.
Or, ask the user to only use this feature when connected to a charger or external battery pack.
Or, ask the user to jiggle their device every few minutes for a few moments, to try to convince Android that it is not sitting idle on a nightstand.
Or, build your own custom ROM, where you take steps to modify Android to allow your app to consume arbitrary amounts of power, then have users install your custom ROM.
Note that AFAIK your GCM solution would need to be every minute, not every five minutes, if you want to send "pings" every minute. The GCM solution does not prevent the device from going into Doze mode; it merely allows you to send messages to the app and have a brief window of connectivity. It is possible that the window is 5+ minutes, but I wouldn't count on it.
Note that you are saying, in effect, that the CPU will need to be on continuously for your 2-3 hour window, due to your partial WakeLock. You are also saying that some radio (WiFi or cellular) will be in a high-power mode for much of that time as well, since they go through a series of power states with relatively slow transition times, and an every-minute set of packets will push the radio back into the high-power state. What you are doing is exceptionally bad for battery life.
If your users agree that what you are doing is "incredibly important" to them, they will not mind adding you to the whitelist, or only using this feature while on a charger.
I'm trying to develop an Android app that among other things, uses location services to get user location and sends it to a remote server. The user can turn this feature on and off according to his own will, but as long as it's turned on, it will get user location periodically (maybe each 30 seconds, don't know it for sure yet). Also, while it is turned on, it must keep tracking the user even if the application is closed.
So far I've considered 2 options:
Option 1 - Use Service, call startForeground to make sure Android don't kill it (the sticky notification is not an issue to me) and use a LocationListener with the said interval, but this seems rather inefficient as the service would be doing nothing most of the time, I mean, the listener would be called each 30 seconds, send the location to the server and the service itself would spend the next 29.9 seconds or whatever just waiting for the next location.
Option 2 - Doing some research, I've seen some approaches using AlarmManager to trigger some background service (like seen in this post), but I'm concerned that using alarms that often (every 30 seconds) might not be good for the battery and system general performance (in a code snippet in this page of Android's Developer guide there's a comment saying that "hopefully your alarm will have a frequency lower than 30 MINUTES").
Maybe there's another option that I still haven't thought about, or maybe there's a way to put the service from option 1 to sleep for some time or something like that. Bottom line, I'm looking for the approach that doesn't impacts on performance, consumes the minimum amount of battery and has the least chance of being killed by Android.
Any help and/or suggestions are welcome.
I have application which for every 10 seconds do some request to server (http client). I read a lot about application life cycle. My application has service with foreground flag and it's work well (application work all time) when android is "active". I don't have phone with real android, so I am testing on emulator, but my friend testing it on smartphone and he notice that when he leave his phone, request are post for 10, 30 minutes, even hour. If he turn on screen, then request time is back to 10 seconds (he have access to server so he see logs). Is this known behavior? Because he installed gmail notifier from google, and this same problem (big delay). Any solution for this? My service have timer task (so request is sent in async task)
Regards
First of all, if you're polling every 10 seconds, that's gonna drain a lot of battery and network bandwidth.
I recommend using a lower frequency or server push.
For the polling issue, how do you implemented the polling ?
Do you use timers ? if so, what options do you pass in ? Or do you use a thread that sleeps for 10 seconds ?
Depending on the version, Android may turn off all processes, or delay network requests to run every 30 minutes to preserver battery power and bandwidth. (Starting up the network components drain a lot of battery than keeping them running. So If your app turns ON network, do a poll, then simply turn it off, Android may schedule it to align with all other requests on the system.)
Can you provide us more info about how you do the polling ?
UPDATE
You might have to schedule a 'WakeLock' so android knows when to wake up for your service. I think, by default, android doesn't wake up for timer requests that are scheduled very frequently and it schedules them as I explained. WakeLocks on the other hand can force android to wake up.
See this question and WakeLock Documentation
Make sure you pass the correct parameters, so you don't turn the screen ON. (Would be really annoying.)
UPDATE
I still recommend using server push for this, which will save battery and bandwidth while keeping the updates real time.