45

I want a service to run all the time in my application. So I want to restart it even if it is force closed by user. There is definitely a way to do it as apps like facebook are doing it.(Its not done using push notification, facebook restarts its service even if internet is off).

Any help would be appreciated. Thanks!

Vipul J
  • 6,393
  • 9
  • 43
  • 60

10 Answers10

70

First of all, it is really very bad pattern to run service forcefully against the user's willingness.

Anyways, you can restart it by using a BroadcastReceiver which handles the broadcast sent from onDestroy() of your service.

StickyService.java

public class StickyService extends Service
{
    private static final String TAG = "StickyService";


    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand");
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        sendBroadcast(new Intent("YouWillNeverKillMe"));
    }

}

RestartServiceReceiver.java

public class RestartServiceReceiver extends BroadcastReceiver
{

    private static final String TAG = "RestartServiceReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "onReceive");
    context.startService(new Intent(context.getApplicationContext(), StickyService.class));

    }

}

Declare the components in manifest file:

    <service android:name=".StickyService" >
    </service>

    <receiver android:name=".RestartServiceReceiver" >
        <intent-filter>
            <action android:name="YouWillNeverKillMe" >
            </action>
        </intent-filter>
    </receiver>

Start the StickyService in a Component (i.e. Application, Activity, Fragment):

startService(new Intent(this, StickyService.class));

OR

sendBroadcast(new Intent("YouWillNeverKillMe"));
lgdroid57
  • 623
  • 12
  • 27
Mehul Joisar
  • 14,908
  • 5
  • 44
  • 54
  • 1
    Agree, it is. But have to do it. – Vipul J Feb 04 '14 at 11:36
  • This does not work for me. Nothing seems to work actually. I tried using an AlarmManager triggered service as well. – Sohaib Apr 15 '15 at 09:57
  • @Sohaib: it is working fine for me. can u provide more info about your case? android version, code etc. – Mehul Joisar Apr 15 '15 at 11:14
  • 1
    Have a look at this: http://stackoverflow.com/q/29607856/1901744. Android version is 4.4.4. – Sohaib Apr 15 '15 at 11:22
  • 23
    As far as I know if user force stops an application BroadcastReceivers won't work anymore – sadegh saati Jun 16 '15 at 23:23
  • A SOLUTION that would work even if onDestroy isn't called everytime: send a broadcast from your service every one second and create a receiver that receives those broadcasts. Get the ellapsed time since the last broadcast message. If it is (a lot) greater than 1 second then your service isn't alive anymore -> restart it. Hope this helps – sjkm Sep 22 '15 at 16:01
  • 2
    @sjkm Isn't that battery killer? – Joaquin Iurchuk Oct 28 '15 at 17:51
  • @joaquin Hi, no it is not really. A call every one second or few seconds is nothing. You probably won't notice anything... – sjkm Oct 28 '15 at 17:55
  • if we force stop the app , no instance of app there in the device, then where you calculate the elapsed time? one solution i found is ping server from service , and check the ping is getting every time interval , if the ping stops, send a gcm notification from server, and on receiving the gcm broadcast restart the service. but it is very costly and comlex – Jovin Nov 09 '15 at 13:04
  • @sjkm i am pretty sure it won't work. the logic is good, but won't work. Could you say where you calculating ( _If it is (a lot) greater than 1 second then your service isn't alive anymore -> restart it_ ) and restarting the service again ? – Jovin Nov 11 '15 at 09:12
  • Since Android 3.1, apps that are in the stopped state do not receive broadcast Intents, nor gcm push messages. – MikeL Jan 26 '16 at 21:37
  • what if I start the same service again from there without broadcasting ? – droidev Apr 29 '16 at 07:10
  • 18
    Not working when user force close the app. **onDestroy** isn't called. – Amitai Fensterheim Jul 12 '16 at 23:54
  • 2
    "First of all, it is really very bad pattern to run service forcefully against the user's willingness." -> that s what Google do all time... – ChrisUser2627250 Jul 19 '17 at 13:19
  • 2
    In some phones like Mi and Vivo, we have to change the settings and give the app special permission to run in background from the settings app. Even if you have made a service that auto-restarts when the app is closed, the service won't run until and unless you set permissions in the settings app of your phone. – Gaurav Bharti Jun 02 '18 at 10:23
  • Try it with `adb shell am crash [my_pid]` – IgorGanapolsky Oct 07 '20 at 15:07
16

You have to create a sticky service with overriding onTaskRemoved method, where you can set an alarm service to trigger your code again.

public class BackgroundService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        //create an intent that you want to start again.
        Intent intent = new Intent(getApplicationContext(), BackgroundService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 5000, pendingIntent);
        super.onTaskRemoved(rootIntent);
    }
}

Also in some devices like Xiaomi, Huwaei the app gets force closed once it's removed from recent apps. This is because the manufacturers have task manager features which improve ram/battery performance.

You can check this link for more information: https://stackoverflow.com/a/41360159/2798289

Govind
  • 2,142
  • 22
  • 38
5

As per the Android document

Starting from Android 3.1, the system's package manager keeps track of applications 
that are in a stopped state and provides a means of controlling their launch from 
background processes and other applications.

Note that an application's stopped state is not the same as an Activity's stopped
state. The system manages those two stopped states separately.
FLAG_INCLUDE_STOPPED_PACKAGES — Include intent filters of stopped applications in the
list of potential targets to resolve against.

FLAG_EXCLUDE_STOPPED_PACKAGES — Exclude intent filters of stopped applications from the
list of potential targets.

When neither or both of these flags is defined in an intent, the default behavior is to
include filters of stopped applications in the list of potential targets. 

Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents.
It does this to prevent broadcasts from background services from inadvertently or
unnecessarily launching components of stopped applications. A background service 
or application can override this behavior by adding the FLAG_INCLUDE_STOPPED_PACKAGES
flag to broadcast intents that should be allowed to activate stopped applications.

On Force stop of app, Android just kill the process ID. No warnings, callbacks are given to service/activities. As per the Android document, When the app is killed there are chances that it calls onPause().

When I tried in my app, even onPause() was not called. I think the only way is use to FLAG_INCLUDE_STOPPED_PACKAGES intent flag and send it from another app

Zohra Khan
  • 4,674
  • 3
  • 22
  • 32
3

If I understand correctly, then actually this is not possible, Android feature to force close application was designed to allow user to get rid of unwanted applications, so it disallows any activities from it until user again starts any of its Activity.

Restart the service even if app is force-stopped and Keep running service in background even after closing the app How?

Community
  • 1
  • 1
marcinj
  • 44,446
  • 9
  • 70
  • 91
  • 1
    It is, as I mentioned other apps are doing it – Vipul J Feb 04 '14 at 11:12
  • It appears that KitKat brought some changes in this matter, look in here: https://groups.google.com/forum/#!topic/android-developers/H-DSQ4-tiac. Author workaround is: "The workaround I'm using is very simple: I create a transparent activity from onTaskRemoved to restart my services. How dirtier can it get?" – marcinj Feb 04 '14 at 11:48
3

Whenever a service is killed, its onDestroy method is always called. Its better to use a BroadcastReceiver to start your service when it is killed.

Here is a sample code illustrating its implementation:-

@Override
public void onDestroy() {
Intent in = new Intent();
in.setAction("StartkilledService");
sendBroadcast(in);
Log.d("debug", "Service Killed");
}

Then register a receiver in AndroidManifest.xml:-

<receiver android:name=".app.ServiceDestroyReceiver" >
    <intent-filter>
        <action android:name="StartKilledService" >
        </action>
    </intent-filter>
</receiver>

Finally,create a BroadcastReceiver,and start your service in the onReceive method:-

@Override
public void onReceive(Context context, Intent intent) {
Log.d("debug", "ServeiceDestroy onReceive...");
Log.d("debug", "action:" + intent.getAction());
Log.d("debug", "Starting Service");
ServiceManager.startService();
}

Hope this helps.

Atish Agrawal
  • 2,805
  • 1
  • 17
  • 34
2

on the service's startCommand method return START_STICKY. generally it tell the OS to start the service when it is killed.

Bijesh
  • 307
  • 3
  • 10
2

If the situation allows to use 'root' it's usually possible to implement Humpty-Dumpty paradigm.

Your application (1st) installs another application (2nd, taking APK from assets) and runs the service of the 2nd app. 2nd app's service bind to the 1st app service and rebinds when disconnected. The 1st app does the same.

Sure it will not help when all apps are killed by some Free RAM or similar application but when Android kills either of those two, the other one will restart its counterpart.

OGP
  • 886
  • 2
  • 11
  • 25
1

The only real solution for keeping services alive ist to call Service.startForeground(...) with a provided Notification. This will be the only valid solution, every other one will be very dependent on how Google will change the behaviour of it's system. With every API update, Google could prevent every other hack.

This also keeps the user aware, that your app is performing some background task which will keep the app alive and the user has to stop this. If you provide the user the ability to stop it is part of your application, though.

See the Documentation:

void startForeground (int id, Notification notification)

Make this service run in the foreground, supplying the ongoing notification to be shown to the user while in this state. By default services are background, meaning that if the system needs to kill them to reclaim more memory (such as to display a large page in a web browser), they can be killed without too much harm. You can set this flag if killing your service would be disruptive to the user, such as if your service is performing background music playback, so the user would notice if their music stopped playing.

da_berni
  • 501
  • 4
  • 12
0

There is a very hacky solution to keep service running even you force stop it. I do not recommend that because it is against user willingness. You can define a broadcast receiver to receive intent with action X. onStartCommand handler of your service, broadcast X (if the service is not started yet). on broadcast receiver upon receipt of X, first start the service, then, sleep for some minutes, and finally re-broadcast X.

Nami
  • 1,190
  • 10
  • 20
-2

I think the only foolproof solution here is to have 2 services in separate processes (android:process="somecustomprocessname" in manifest, in the service entry) that both listen to broadcasts and restart each other, because currently the UI doesn't let users kill multiple processes in one action. You can then set up a pinger thread in each service that checks if the other service is running every 100 milliseconds or so, and if not, attempts to restart it. But this is starting to look more and more like malware...

Megakoresh
  • 505
  • 10
  • 29
  • This is malware from day 1 on. You simply shouldn't do that. Use Foreground Services for long living background work. – da_berni Nov 05 '18 at 13:11
  • @da_berni I think people are supposed to read both the question, response and the date of both before throwing votes around. – Megakoresh Nov 06 '18 at 13:28