I have an app which is heavily based on C++ (NDK), with it comes a lot of state which is non trivial to be put in a bundle or use some other method to persist it. The app allows users to modify photos etc, so the size of file in memory can get pretty big which can make the saving operation run a little longer (3-4 secs) than what Android would allow.
Previously, I had found that starting a foreground service in onPause allowed us to keep the process alive just long enough for us to carry our work. And even though Android-12's foreground service restrictions do allow foreground services to be run during the onPause transition, but I've discovered that this isn't true for all OEMs (specifically Samsung devices have lots of ForegroundServiceStartNotAllowedException).
So my question is, is there a way I can keep process alive just a little longer for the saving operation to finish?
I've tried my luck with WorkManager when I read the setExpedited allowed the job to be run immediately (and on older devices this would just start a foreground service, so this seemed very similar to my previous approach but with added benefit of supporting newer devices). But I discovered that this isn't fast enough to escape the slaughter brought down on Android's UI thread.
PS: If it is relevant, all the saving is a simple disk I/O operation not a network one.
Related
While testing the background execution limits as stated here I created a thread in my service. Something like this :
// spawn own thread
HandlerThread thread = new HandlerThread("TestServiceThread");
thread.start();
The service is started by the usual pre Oreo startService.
What I noticed while debugging in android device monitor is that the threads I create continue to live long and healthy and execute normally. Can this be a workaround to keep abusing system resources and not do things via foreground services or jobs ? or is it just a chase against the framework which will soon end ? Any comments ?
I wouldn't expect that to change. Its impossible (not just in Android, its theoretically impossible) to safely kill a thread without the thread helping out. Otherwise you could kill the thread in a condition where other threads will deadlock, have inconsistent data, or the app may just not function. That's why thread.stop() is deprecated- because there is no way to make it safe. And that's why you interrupt a thread instead, and the thread needs to monitor isInterrupted and exit cleanly.
I would be careful with this kind of approach.
Although Gabe Sechan's answer is quite valid, the danger of relying on this working is too high to pursue this. Google are clearly out to get any app that tries to do background execution and abuses the user's battery and for good reason in my opinion. Some apps just don't respect a user's battery at all.
The documentation clearly states:
An app is considered to be in the foreground if any of the following
is true:
It has a visible activity, whether the activity is started or paused.
It has a foreground service. Another foreground app is connected to
the app, either by binding to one of its services or by making use of
one of its content providers. For example, the app is in the
foreground if another app binds to its: IME Wallpaper service
Notification listener Voice or text service If none of those
conditions is true, the app is considered to be in the background.
Source:
https://developer.android.com/about/versions/oreo/background.html#services
Although it's not safe to kill a thread due to all the reasons mentioned by Gabe, Android could well kill the app off entirely (ala kill -9). I would imagine that any deadlocks would be handled by Android (not a trivial task I'm sure). Data corruption would be considered as the app's fault for not handling background execution properly.
It's a bit of a risk for Android but they've probably weighed it up and decided this is the way to go.
Also, take care of this:
Note: By default, these restrictions only apply to apps that target
Android 8.0 (API level 26) or higher. However, users can enable most
of these restrictions for any app from the Settings screen, even if
the app targets an API level lower than 26.
Source: https://developer.android.com/about/versions/oreo/background.html#overview
I am developing a simple app that just play a white noise sound in background while I am doing other things.
It works very well when I switch to other apps ( like games, chrome browser, etc ) but sometimes ( for example when there are many chrome tab opened ) the white noise sound stop and I need to reload my app.
I am NOT using Services, is this the reason ?
Because your apps is getting killed by the system to give up resources for to other apps (games, chrome, etc). So you need to use a Service.
Here an excerpt from Processes and Application Life Cycle
for more details explanation:
An unusual and fundamental feature of Android is that an application
process's lifetime is not directly controlled by the application
itself. Instead, it is determined by the system through a combination
of the parts of the application that the system knows are running, how
important these things are to the user, and how much overall memory is
available in the system.
...
A cached process is one that is not currently needed, so the system is free to kill it as desired when memory is needed elsewhere. In a
normally behaving system, these are the only processes involved in
memory management: a well running system will have multiple cached
processes always available (for more efficient switching between
applications) and regularly kill the oldest ones as needed. Only in
very critical (and undesirable) situations will the system get to a
point where all cached processes are killed and it must start killing
service processes. These processes often hold one or more Activity
instances that are not currently visible to the user (the onStop()
method has been called and returned). Provided they implement their
Activity life-cycle correctly (see Activity for more details), when
the system kills such processes it will not impact the user's
experience when returning to that app: it can restore the previously
saved state when the associated activity is recreated in a new
process.
I think Services is What You are looking For.
A Service is an application component that can perform long-running
operations in the background, and it does not provide a user
interface.
For better chance of preventing OS to kill your app, you should use a
Foreground Service
following the official guide here: https://developer.android.com/guide/components/services.html#Foreground
Remember that there is no way to be certain that OS will never kill your app, because when RAM becomes really low it could kill every process indipendently from type, following his priority rules
I'm working on an Android app to be used in an experiment we are running in our lab. The application monitors the users movement using the accelerometers, performs calculations on this data at a regular interval, and writes the results to a file.
I'm currently having a very difficult time trying to find a way to run this process for the 15-20 minutes our trials require without it being killed. Despite declaring applications persistent, trying various service approaches (startForeground(), START_STICKY, ..), etc... I cannot seem to keep the Android OS from deciding to pause or kill my service/process.
I've done some research and the only advice I can find is how to set up your processes to gracefully recover from being killed, however I cannot afford to have gaps in my data and therefore need this process to run continuously.
Could someone point me in the right direction?
From documentation I get the impression that if you want to have a service that will only be killed in extremely low memory situations you need to:
startForeground() (you have done that)
START_STICKY (you tried that too) or START_REDELIVER_INTENT (restarts service if it is killed, but that leaves gaps in your data)
run all its processing in a separate thread
use Context.startService() to start service
The only sure way is to have it as a system daemon.
The best solution I could come up with for my problem is increasing the screen sleep delay on the device to 30 minutes and pray no buttons were pressed during our trials.
I am working on an Android application that collects sensor data over the course of multiple hours.
For that, we have a Service that collects the Sensor Data (e.g. Acceleration, GPS, ..), does some processing and stores them remotely on a server.
Currently, this Service runs in a separate process (using android:service=":background" in the manifest). This complicates the communication between the Activities and the Service, but my predecessors created the Application this way because they thought that separating the Service from the Activities would make it more stable.
I would like some more factual reasons for the effort of running a separate process. What are the advantages? Does it really run more stable? Is the Service less likely to be killed by the OS (to free up resources) if it's in a separate process?
Our Application uses startForeground() and friends to minimize the chance of getting killed by the OS.
The Android docs are not very specific about this, the mostly state that it depends on the Application's purpose ;-)
TL;DR What are objective reasons to put a long-running Service in a separate process (in Android)?
Reduced RAM Usage
The Android developer documentation suggests this might be appropriate to keep the service's RAM usage down.
From Managing Your App's Memory: Use multiple processes:
An example of when multiple processes may be appropriate is when building a music player that plays music from a service for long period of time. If the entire app runs in one process, then many of the allocations performed for its activity UI must be kept around as long as it is playing music, even if the user is currently in another app and the service is controlling the playback. An app like this may be split into two process: one for its UI, and the other for the work that continues running in the background service.
So running the service in a separate process could consequently reduce performance impact of the app while also reducing the likelihood of the service being killed when the system is low on RAM.
Reduced Performance Impact
From Managing Your App's Memory: Switching Apps:
If your app has a cached process and it retains memory that it currently does not need, then your app—even while the user is not using it—is constraining the system's overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache beginning with the process least recently used, but also giving some consideration toward which processes are most memory intensive.
Reduced Likelihood of Being Killed
From Managing Your App's Memory: Release memory as memory becomes tight:
Note: When the system begins killing processes in the LRU cache, although it primarily works bottom-up, it does give some consideration to which processes are consuming more memory and will thus provide the system more memory gain if killed. So the less memory you consume while in the LRU list overall, the better your chances are to remain in the list and be able to quickly resume.
So your service is less likely to be killed when it's in a separate process since the process's RAM usage will be smaller since the service isn't sharing UI resources.
When to do this
If your service doesn't use startForeground(), I've found that Android will just kill it when it needs to free up RAM, so the service's RAM consumption isn't too important. So if you're just considering the performance impact on the OS and other apps, I don't think it's worth running the service in a separate process.
However, if you do use startForeground(), Android will try to keep your service alive as much as possible, so any RAM that the process uses will impact the OS and other apps. So in this case, I recommend using a separate process, which could save at least 10MB of RAM, so you don't slow down your users' devices.
Also, note that making your app multi-process is not easy; Android's SharedPreferences doesn't support multiple processes.
The first place to start is by reading through the description of component lifecycles. The take away from that is you really are not guaranteed that a Service or other component will be allowed to run for a long period of time.
However, it does sound like a Service is the right choice for the functionality you describe. This is because you are doing some operations that are not user facing. Going back to the lifecycle description, any time an Activity is not in the foreground, it is essentially a candidate for being killed.
What you should consider doing is using AlarmManager to periodically trigger your Service. You might want also to look at using the WakefulIntent library that #CommonsWare has created.
There is a good article describing multitasking and processes on the Android blog called Multitasking the Android Way that might get at some of the more details regarding processes you are interested in. For example:
A common misunderstanding about
Android multitasking is the difference
between a process and an application.
In Android these are not tightly
coupled entities: applications may
seem present to the user without an
actual process currently running the
app; multiple applications may share
processes, or one application may make
use of multiple processes depending on
its needs; the process(es) of an
application may be kept around by
Android even when that application is
not actively doing something.
Running a service in its own process has the small advantages that the garbage collector for the service does not affect your application and that the memory footprint of the service is a bit smaller if it runs alone.
If consumption of the service by other applications is not a requirement for you, prefer a local service. Alternatively you can still run the service in its own process and use different communication with your application, e.g. via a broadcast receiver. See Android service tutorial for details.
Separating the service to run in a different process doesn't make it more stable, but in some cases, makes your application more stable, since if this service crashes, your application will not crash with it, and can recover.
Eli
Is there something in the Android developer guidelines that disuades developers from providing the option to "exit" (stop running) an application from within the application itself?
I love multitasking and all but it's not clear to me why:
the vast majority of apps don't have their own Exit functions and hence just keep running forever
don't give you a choice about running when you turn on the phone - they just do by default
Both of these things lead to memory usage constantly increasing and your device running with this performance burden all of the time despite the fact that you may only want certain apps to run some of the time.
Am I missing something?
Is there something in the Android
developer guidelines that disuadea
developers from providing the option
to "exit" (stop running) an
application from within the
application itself?
Yes. It is generally not needed, just as it is generally not needed to restart a Web server because some user with a browser decided (s)he is done with a Web app.
the vast majority of apps don't have
their own Exit functions and hence
just keep running forever
They don't keep running forever. Android will close things up as needed.
don't give you a choice about running
when you turn on the phone - they just
do by default
Those developers aren't paying attention to me.
Both of these things lead to memory
usage constantly increasing
Generally, it doesn't. If you find specific apps that do this, uninstall them.
and your device running with this
performance burden all of the time
Generally, it doesn't. If you find specific apps that do this, uninstall them.
Also, this question is a duplicate of this one.
"Both of these things lead to memory usage constantly increasing"
Which doesn't matter since Android apps are limited to a fixed amount of RAM. Freeing RAM won't give more RAM to other apps.
Essentially, there's no need for a quit button as long as the developer does a good job of designing their app. Android activities are stopped when they aren't visible and resources are needed elsewhere, so the are no longer consuming resources. You can read about the lifecycle here:
Here's a related question:
From Google's Android Application Fundamentals page:
Shutting down components
A content provider is active only while it's responding to a request from a ContentResolver. And a broadcast receiver is active only while it's responding to a broadcast message. So there's no need to explicitly shut down these components.
Activities, on the other hand, provide the user interface. They're in a long-running conversation with the user and may remain active, even when idle, as long as the conversation continues. Similarly, services may also remain running for a long time. So Android has methods to shut down activities and services in an orderly way:
An activity can be shut down by calling its finish() method. One activity can shut down another activity (one it started with startActivityForResult()) by calling finishActivity().
A service can be stopped by calling its stopSelf() method, or by calling Context.stopService().
Components might also be shut down by the system when they are no longer being used or when Android must reclaim memory for more active components. A later section, Component Lifecycles, discusses this possibility and its ramifications in more detail.
So it seems like Content Providers and Broadcast receivers should never be explicitly shut down, as they are inert while not handling their specific events.
As for Activities, I would argue in favor of having an end to it, but in certain cases. If your app has a finite state in which the user is done using it, why keep it alive until GC gets it? The activity manager still needs to keep track of that Activity while the user has finished their task. My best example for this is the Calculator. You open it, you have it solve a problem for you, and then you close it. If the onCreate function is so expensive that it's more effective to do onCreate once and then onRestart whenever the user moseys back to your application then you're probably doing something wrong. Maybe I'm misinterpreting how Android handles Activities, and if so I'm always interested in learning more :)
It all comes back to the answer that users want total control of their running and auto-start list and what they do and don't want installed, example: google maps, etc etc. there are no two ways about this.