Question:
What are best practices for a persistent/always-on sensor data collection service in an embedded setting? Permanently attached power source and no user to aggravate with another running service, so no battery life or usability concerns.
Plan:
A local Service, startForeground(), START_STICKY, probably acquiring a PARTIAL_WAKE_LOCK, starting on BOOT_COMPLETED. This will not be a Play Store application. I will have an activity which can bind to the service to get feedback, set preferences, and manually start/stop the service if so desired. Since this will be running on a dedicated device with no UI and will not be reliant on battery power, which should bypass most of the usual concerns with services, is there anything else I can/should do to ensure the service runs at a high priority with the least likely chance it will be killed? Is there a better option than a service implemented in this way?
Background (optional reading):
I've written a multi-threaded Activity-based app which starts via a broadcast receiver on boot completed, runs through validations, runs a data collection thread, a data transmission thread which connects to a remote service, and executes other tasks which aren't pertinent to this discussion. I need to transition to a Service-based solution. From what I've read, best practices for a service which collects sensor data usually involve periodically starting the service via an AlarmManager. This will not work in my case.
In general, there's no issue with a Service receiving sensor data. But, be sure that you are processing any data on a background thread rather than in the SensorListener callbacks. If you need to keep receiving data even when the screen turns off, you'll need to hold a partial wakelock to prevent the system from going to a lower power state. Battery life is affected with the "foreground" service only because you are leaving the sensor activated at some interval. Otherwise, there's nothing magical about a service being considered foreground, other than it has a very low chance of being killed off by the framework.
You may also need to make sure the accuracy of the sensor doesn't change (via the listener callback) and if it is different than what your algorithms expect, you'll have to re-configure it with the SensorManager. An Activity based solution won't really do what you are talking about as the Activity is only "running" when it is visible to the user.
Related
I am working on an Android project and I need the app to work even when the device is locked.
The idea is to open the app that will start the (Intent)Service, the service processes the data all the time. The device can be locked/put away and after some time when the app is opened the service is manually stopped. The service should be running all the time in the background.
I have found information online, but I am not sure what to use and in which way..
I have found that the IntentService can be used. Also the service should run in a new thread. I need to process the data from gps all the time, should I use WakefulBroadcastReceiver?
Thank you.
IntentService is not necessarily what you want to use. It will automatically spawn a new thread just to handle an incoming Intent. Once all incoming Intents have been handled it will stop the Service. To have a long running Service, you would need to derive from Service and when it is started return START_STICKY from the onStartCommand() method, plus spawn your own thread to handle your background work.
If you need to monitor GPS, you'll have to manage that along with keeping the device awake using a WakeLock. Note that in Marshmallow, this gets more complicated because of the new Doze mode where even wakelocks are ignored.
Also, note that the way Android is architected there is still a chance that your application running the background Service may be killed. Android uses a unique process management technique based on memory pressure and user perceived priority to determine how long a process should stick around. I recommend reading up on the Service lifecycle in the documentation.
In android their is no fool proof way to ensure that your service runs forever because the LMK(low memory killer) when the system needs resources (based on a certain memory threshold) , kills the service then if it can restarts it. If you handle the restart properly the service will continue to run.
Services that are given foreground priority are significantly less likely to be killed off, so this might be your best bet. However their will be a notification of your service running the in the background on the menu bar up top. Foreground Service
I am designing an application which will collect different data from a lot of sensors and store them in a db, continuously. Sensors that I am using are like Google Play's fused location provider and activity detection. (There is some UI as well, but the UI will barely be launched, so almost everything is happening in the background)
I got two different ways to do this:
1) Start a longliving Service
So I would start a long-living service (with the STICKY flag), that would run in the background. The service would just register for periodic location and activity updates and - in between the updates - just do nothing.
Pros: App is only initialized once
Cons: Service is running 24x7
2) Register PendingIntent and use shortlived IntentService
Now Google Play's Location provider support registration of PendingIntent instead of callback [see here](https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient%2C%20com.google.android.gms.location.LocationRequest%2C%20android.app.PendingIntent) which is even recommended for background tasks.
Pros: The app can get 'shut down' between sensor events
Cons: Each IntentService might re-start the app if it was shut down inbetween, which probably has quite an overhead (initialize db, read shared prefs, initialize all classes, ...)
So my question is: Is it still recommended to use many short lived IntentServices for this kind of app? I haven't done any measurements yet, but I am worried, that each IntentService (and they will be launched quite often), re-starts my app, so that I end up spending more CPU time on initialization, etc. then just having a long-lived service lying dormant.
Anybody has experience with this?
I would like to create an Android application with real-time monitoring functions. One monitoring function is to audit the audio flow. The other function is to interact with a peripheral sensor. These monitoring functions can be triggered by others.
Besides, in order to save power consumption, the audio function will be running in a polling mode, i.e. sleep for a certain amount of time and wake for a certain amount of time.
I am considering how to design the Android application.
Whether to design the audio function as a Service or an Activity?
The problem is if it is designed as an Activity, the audio function will be off if screen turns off after a period of time.
How to design the polling function? Use an AlarmManager or a inner-thread with Timer?
My goal is to save the power consumption as much as possible. Thanks.
I would recommend following
a) Use a Service. Activity is short lived entity (it works only while it's on the screen)
b) Make the service foreground (read this: http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification). This will decrease the chance that system will kill your service
c) In the service, start a thread and do everything you need in the thread.
d) If you want execute periodically, just do Thread.sleep() in the thread (when Thread sleeps it doesn't consume CPU cycles).
I believe c) and d) is preferable to AlarmManager.
Here is piece from documentation (http://developer.android.com/reference/android/app/AlarmManager.html) : "Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler."
Since your application running it's better to have some permanently running thread and execute something on it. Generally speaking Handler, HandlerThread, MessageQueue are just convenience classes for more complex message handling and scheduling. It looks like your case is quite simple and usual Thread should be enough.
Concurring with Victor, you definitely want to use a Service, and pin it into memory by calling startForeground()
However I suggest you look into utilizing the built in system Handler ; place your functionality in a Runnable and call mhandler.postDelayed(myRunnable, <some point in future>) ; this will allow the android framework to make the most of power management.
That's a service.
And you may want some extra robustness: the service can be killed and NOT restarted later, even being a foreground service. That will stop your monitoring.
Start your service from the UI. If you want the service to survive device reboot, also start it from a BroadcastReceiver for android.intent.action.BOOT_COMPLETED.
Create a thread in the service as described in other answers here.
Additionally, use Alarm Manager to periodically start your service again. Multiple startService() calls are OK. If already running, the service will keep running. But if it's been forgotten by the system, say, after a series of low resource conditions, it will be restarted now.
Schedule those alarms responsibly: to be a good citizen, set the absolutely minimal frequency. After all, Android had some good reasons to kill the service.
With some services, even more steps may be needed, but in this case this approach seems to be sufficient.
The app needs an underlying feature that picks up locations and sends them to a server. This must happen regularly (approx every 1-5mins) but most importantly it must happen all the time, never stopping, protected against the OS shutting processes down to reclaim memory, and when the app itself is not running.
The following solutions have been suggested to me. I'm familiar with handling Android locations, the issue here is to ensure they continue, even if the app is not in memory, and to persist through memory reclaims.
SERVICE. Use a service to collect location events and handle them. Use the boot and screen-on broadcasts to ensure the service is always running (and possibly also increase the service priority to protect from memory reclaims).
ALARMS. I gather these can be shut down when memory is short. How would I protect against that? This seems an ugly solution as the locations will arrive on a schedule anyway, so it seems unnecessary to have another time-based component.
LOCATIONS VIA BROADCAST. Locations delivered via a broadcast intent would mean I can then handle the location events in a broadcast receiver. Will these location alerts continue indefinitely? Will anything other than device shutdown or the app turning them off cause them to stop?
What's the most durable approach?
This must happen regularly (approx every 1-5mins) but most importantly it must happen all the time, never stopping, protected against the OS shutting processes down to reclaim memory, and when the app itself is not running.
This is not strictly possible, on a variety of fronts.
Let's take them one piece at a time:
This must happen regularly (approx every 1-5mins)
You may not be able to get locations, period, let alone every 1-5 minutes. The user might have all location providers disabled. The user might have the device in airplane mode. The user might be in a large building (blocking GPS) with poor connectivity (making the network provider unreliable).
never stopping
The user can always get rid of you via the Manage Services screen in Settings or a task killer. If they do so, particularly on Android 3.1+, your app will never run again for any reason until the user starts an activity of yours (e.g., via the launcher). The user could also uninstall your app, of course.
protected against the OS shutting processes down to reclaim memory
You cannot guarantee against this. You can reduce the odds, but that is it.
Now, let's look at your various solutions:
Use a service to collect location events and handle them.
From the way you phrase this (and subsequent sentences), you mean an everlasting service, one that is designed to run 24x7. By definition, this means that your app is running, which violates one of your rules. Assuming you relax this rule, this solution massively increases the odds that the user will get rid of your service, and it increases the odds that Android will get rid of your service. You can minimize the latter by use of startForeground().
ALARMS. I gather these can be shut down when memory is short.
Not that I am aware of. However, if the user gets rid of you, your alarms will be removed.
This seems an ugly solution as the locations will arrive on a schedule anyway
No, they will not. The time parameter on requestLocationUpdates() does not mean that "locations will arrive on a schedule anyway".
Locations delivered via a broadcast intent would mean I can then handle the location events in a broadcast receiver.
No, you cannot. You have indicated that part of your work will be to send this data to a server. You cannot reliably do that on the main application thread, as it may take too long. A getService() PendingIntent, pointing to an IntentService would be more reliable.
Will these location alerts continue indefinitely?
No. See below.
Will anything other than device shutdown or the app turning them off cause them to stop?
The user can get rid of your app (uninstall, task killer, Manage Services). The user can disable location providers. The user may enter an area where the location cannot be determined. Etc.
Also, the device may fall asleep, AFAIK. It's possible the system keeps a WakeLock for the duration of your registered request for updates. It's even possible that the system will use AlarmManager internally to arrange to wake itself up on your supplied period, so it does not have to keep the device awake continuously. However, you will want to test this thoroughly.
What's the most durable approach?
If the concerns in my previous paragraph are handled by the OS, your third option is probably the most robust. Use startForeground() in your IntentService() and call stopForeground() just before exiting onHandleIntent() -- even short-lived services started by AlarmManager may get killed off due to low memory, much to my surprise.
That being said, your desired behavior seems like it may consume more battery life than the user might want. Please allow the user to control the polling period, including an option for "never poll, I'll update things manually".
I have an Android app that runs a background service that collects sensor reading every second.
I have found out that if there are other apps running, I do not collect my data every second (I have missing seconds).
I assume that the OS does not give me sufficient CPU time.
Can I change my service's priority, among the running tasks, so it will get a sufficient amount of CPU and complete it purpose?
(The service is called from an activity using StartService(mIntentService).)
The easiest would be to use startForeground() function that notifies the system to treat the service as a task user know about and would be disruptive to pause or terminate, so it will receive the same attention as the running apps.
You need to provide Notification object so the user is informed about the running service.