14

UPDATE: Previously I couldn't find a well defined pattern as to when my foreground service was being killed. After more debugging with the devices (doesn't happen on all) on which this was happening I found.

1.) A lot of times when I open chrome to load a website the foreground service gets killed. Sometimes even when I am using whatsapp this happens.

2.) There are no exceptions and the stacktrace doesn't show anything useful.

Original Question below:

There are many such questions on StackOverflow but the answers so far that I have read mostly say that it is upto Android and we don't have 100% guarantee that a foreground service will not be killed. Some answers suggest START_STICKY but that is not much helpful in my case.

In my case I have a music player app which has a foreground service. This service gets killed on certain devices, mostly some versions of Xiomi (Android version was 5.1.1). Now I understand that android might be short on memory and so my foreground service is being killed, but then why do other music player apps never go through such termination. What is it that they are doing right that I am not?

I made my service foreground service by using startForeground. Also I return START_STICKY in onStartCommand although that doesn't help because the service is restarted after a period of 4-5 sec if killed. To bind my service with my activity I use

bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT );

So what exactly can I improve/change in my app to prevent this from happening, if other apps are working right there must be something that is wrong in my case. Can someone please help. Thanks in advance !!

Edit:

This is how I call startForeground()

public void sendNotification() {

        Intent notIntent = new Intent(this, MainActivity.class);
        notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendInt = PendingIntent.getActivity(this, 0,
                notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        Bitmap bitmap = null;
        if (!notificationShowing || !forwarded) {
            Log.i(TAG, "present");
            String title = CommonUtils.getSongFromID(songIndex, this);

            bigView.setTextViewText(R.id.title, title);
            bigView.setImageViewBitmap(R.id.img, bitmap);

            smallView.setTextViewText(R.id.title1, title);
            smallView.setImageViewBitmap(R.id.img1, bitmap);

            if (pauseButton == 1) {
                bigView.setImageViewResource(R.id.pause, R.drawable.pause_noti);
                smallView.setImageViewResource(R.id.pause1, R.drawable.pause_noti);
            } else {
                bigView.setImageViewResource(R.id.pause, R.drawable.play_noti);
                smallView.setImageViewResource(R.id.pause1, R.drawable.play_noti);
            }

            musicNotification = builder.setContentIntent(pendInt)
                    .setSmallIcon(R.drawable.logo1)
                    .setTicker(songTitle)
                    .setOngoing(true)
                    .setContentTitle("Playing")
                    .setStyle(new Notification.BigTextStyle().bigText("Song App"))
                    .setContentText(songTitle)
                    .setPriority(Notification.PRIORITY_MAX)
                    .build();

            musicNotification.contentView = smallView;
            musicNotification.bigContentView = bigView;

            musicNotification.contentIntent = pendInt;

            Intent switchIntent = new Intent("pause");
            switchIntent.putExtra("button", "pause");
            PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 100, switchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            bigView.setOnClickPendingIntent(R.id.pause, pendingSwitchIntent);
            smallView.setOnClickPendingIntent(R.id.pause1, pendingSwitchIntent);

            Intent switchIntent1 = new Intent("forward");
            switchIntent1.putExtra("button", "forward");
            PendingIntent pendingSwitchIntent2 = PendingIntent.getBroadcast(this, 100, switchIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
            bigView.setOnClickPendingIntent(R.id.forward, pendingSwitchIntent2);
            smallView.setOnClickPendingIntent(R.id.forward1, pendingSwitchIntent2);

            Intent switchIntent2 = new Intent("previous");
            switchIntent2.putExtra("button", "previous");
            PendingIntent pendingSwitchIntent3 = PendingIntent.getBroadcast(this, 100, switchIntent2, PendingIntent.FLAG_UPDATE_CURRENT);
            bigView.setOnClickPendingIntent(R.id.previous, pendingSwitchIntent3);
            smallView.setOnClickPendingIntent(R.id.previous1, pendingSwitchIntent3);

            Intent switchIntent3 = new Intent("end");
            switchIntent3.putExtra("button", "end");
            PendingIntent pendingSwitchIntent4 = PendingIntent.getBroadcast(this, 100, switchIntent3, PendingIntent.FLAG_UPDATE_CURRENT);
            bigView.setOnClickPendingIntent(R.id.end, pendingSwitchIntent4);
            smallView.setOnClickPendingIntent(R.id.end1, pendingSwitchIntent4);

            startForeground(NOTIFY_ID, musicNotification);
            notificationShowing = true;
        }
        forwarded = false;

    }
varunkr
  • 5,364
  • 11
  • 50
  • 99
  • Can you show how you are calling startForeground() – ucsunil Sep 12 '16 at 17:21
  • did you notice any specific pattern when your foreground service is killed? For example: when you open another music player app or when you open youtube etc.? – AADProgramming Sep 12 '16 at 17:21
  • @AADTechnical No there is no particular pattern, even if I just keep it by itself, it stops after a while – varunkr Sep 12 '16 at 17:53
  • @ucsunil Thanks for the reply, I have added the code !! Thanks – varunkr Sep 12 '16 at 18:09
  • Check whether 'onTrimMemory' being called or not? – Pravin Divraniya Sep 13 '16 at 06:34
  • @PravinDivraniya Hey thnx for the reply, will see this ! – varunkr Sep 13 '16 at 07:13
  • Also check your activity(you bindService from) is destroying or not? Because if it is, then it will also destroy your service(If your activity is only client of service) as you are binding them. – Pravin Divraniya Sep 13 '16 at 08:37
  • @AADTechnical Hey man, after lots of debugging looks like it is very likely to stop when I open chrome or whatsapp, may be if I do any internet related options, though I am not sure. Since u asked if there is a pattern, do you have any advice for me? – varunkr Sep 14 '16 at 15:08
  • Hi @varunkr please look at this answer http://stackoverflow.com/questions/6645193/foreground-service-being-killed-by-android . It describes beautifully how you can debug your service. – Gautam Sep 17 '16 at 06:41
  • @Gautam Thanks for the comment. I have already looked at that answer and my service looks absolutely fine according to it. – varunkr Sep 17 '16 at 07:43
  • Are you running your service in a separate process to your main application? – brandall Sep 19 '16 at 00:43
  • @brandall No I am not. In fact I tried doing this using AIDL, but the changes didn't look feasible to me, that is to say my service and binding activity have lot of code and making these changes look very cumbersome. – varunkr Sep 19 '16 at 05:41
  • You need to decouple the service from other aspects of your application as much as possible. Running it in a separate process is a must, otherwise it will be indirectly attached to your UI memory objects http://stackoverflow.com/q/16153674/1256219 The AIDL is not difficult, it's just an interface really. My application runs entirely as a foreground service and this was the most stable approach. However, it does still get killed occasionally, on lower spec devices or ones with poor memory management. The same happens to music players too.... – brandall Sep 19 '16 at 16:43
  • @brandall Thanks for the info. I see, may be I am overestimating AIDL complexity. Btw my service runs extremely fine on almost all devices except for this Xiomi shit which is a pain in the developer's ass imo. I know about one or two top music player apps on the playstore which run the service in the same process. I will see, if the need arises I will definitely switch to AIDL. Thanks again !! – varunkr Sep 19 '16 at 16:58
  • @varunkr I bought a load of really cheap devices from eBay and it put my mind at ease that it was their fault and not mine! Even so, take a very close look at your memory objects when the player is running and perhaps look to hint to the garbage collector if your service calls `onTrimMemory(int level)` or `onLowMemory()` – brandall Sep 19 '16 at 17:10
  • @brandall Thanks for the info, I will keep this in mind. Thanks again, much appreciated !! – varunkr Sep 19 '16 at 17:29

2 Answers2

9

This happened in Xiomi phone due to below reason.

Solution for MIUI 7.0 => Security => Autostart => select Apps that you want to run in background => Reboot After reboot your device should able to run your application services in background like other android devices do.

MIUI 4.0 settings

MIUI AutoStart Detailed Description

And if you looking for other phone then check here is service structure.It automatically restart but when you restart phone call BootReceiver.

public class AppService extends Service {

private class LocalBinder extends Binder {
    public AppService getServerInstance() {

        return AppService.this;
    }
}


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


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // If we get killed, after returning from here, restart

    return Service.START_STICKY;
}

@Override
public void onCreate() {
    super.onCreate();

} 

@Override
public void onDestroy() {

}

}

Thanks hope this will help you.

Saveen
  • 4,120
  • 14
  • 38
  • 41
1

This service gets killed on certain devices, mostly some versions of Xiomi (Android version was 5.1.1)

Not sure about this, but as per my understanding this might be because of

  1. Bug in os customization from the vendor.
  2. Bugs in Android with respect to prioritizing foreground services, that are triggered by various combinations of service binding flags(i.e. BIND_AUTO_CREATE, BIND_IMPORTANT etc).Read this answer by Robin Davies.

I don't know whether you use startService() or not. But if you don't then as per this documentation:

You can create a service that is both started and bound. That is, the service can be started by calling startService(), which allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService().(This is called Binding to a Started Service)

If you do allow your service to be started and bound, then when the service has been started, the system does not destroy the service when all clients unbind. Instead, you must explicitly stop the service, by calling stopSelf() or stopService().

Although you should usually implement either onBind() or onStartCommand(), it's sometimes necessary to implement both. For example, a music player might find it useful to allow its service to run indefinitely and also provide binding. This way, an activity can start the service to play some music and the music continues to play even if the user leaves the application. Then, when the user returns to the application, the activity can bind to the service to regain control of playback.

Be sure to read the section about Managing the Lifecycle of a Bound Service, for more information about the service lifecycle when adding binding to a started service.

onStartCommand will be called in case of started service so START_STICKY will work in case of startService() only.

Update on process logs

Proc # 5: prcp F/S/IF trm: 0 22407:com.wave.music.player/u0a2 (fg-service)

In your process log your player service running in foreground with adj setting prcp (visible foreground service) which means it's virtually indestructible. Still your service destroyed by OS than there might be very low memory available to run newly launch app. As per this documentation,

There will only ever be a few foreground processes in the system, and these will only be killed as a last resort if memory is so low that not even these processes can continue to run. Generally, at this point, the device has reached a memory paging state, so this action is required in order to keep the user interface responsive.

So I think you are doing nothing wrong. I just want to suggest you to read this official Android developer documentation and try to run your service in separate process(Documentation suggests this approach for music player app). Be careful to implement this as it can easily increase—rather than decrease—your RAM footprint if done incorrectly.

Community
  • 1
  • 1
Pravin Divraniya
  • 4,223
  • 2
  • 32
  • 49
  • Thanks for taking the time to answer. I am using startService() and I am binding my activity to my service. Since this is working well on most of the devices I tested on including Google Nexus, I think this might be due to a bug in os customization from Xiomi. I guess other good music apps might have handled this explicitly. Also I should add that this killing occurs only when the app is minimized/goes in background. Do you think its priority changes after this happens and that is the reason why it gets killed? Thanks for the answer !! – varunkr Sep 13 '16 at 19:37
  • Yes this might be the case. Low priority process is at high risk of being killed by OS in case of low memory. Just a thought, try using Context.BIND_ABOVE_CLIENT flag in bind service might help you. – Pravin Divraniya Sep 14 '16 at 03:55
  • Hey, the device on which the error occurred was my friend's. I got the device from him and tested to see the problems. There were a few observations 1.)Service is more likely to be killed if I am using other apps. I used whatsapp and chrome. Sometimes it crashed as soon as I opened chrome though other times it took some time. 2.)There were no errors or any other imp info in stacktrace. 3.)I also used sysDump as said by R Davies, though I didn't find anything unusual. I have attached it in the edit. Can you think of any problems based on these. I would really appreciate any help. Thanks !! – varunkr Sep 14 '16 at 15:47
  • Sorry the edit was too big, here is the sysdump result https://jpst.it/Nmgz My app is com.wave.music.player – varunkr Sep 14 '16 at 15:51
  • Ok...I will check and let you know if find anything....Did you check with BIND_ABOVE_CLIENT flag? – Pravin Divraniya Sep 14 '16 at 17:35
  • No I didn't so far. In Robin Davies;' answer, he wrote that BIND_ABOVE_CLiENT flag should be avoided, but I will try it since you say. Do tell me if you find anything. Thanks !! – varunkr Sep 14 '16 at 20:49
  • Thanks a lot for taking the time to help. I think your suggestion of running the service in another process might actually do the job. I will try it today and give an update here. Thanks a lot !! – varunkr Sep 16 '16 at 08:17
  • So I tried to do it and I would say that using AIDL is too complicated. I didn't expect that it would be so much work, and not just work, it is really very complex, at least to me. Since my service and activity have a lot of code and I call methods of one in the other one a lot of times, doing this is not feasible in my case. May be I am overestimating it, but that is what my impression was. I would still say that your suggestion was great. But I still feel there would be a way to fix it without using a different process. I will try to find a way. – varunkr Sep 16 '16 at 21:05
  • Thanks a lot for your time, I will award you the bounty if a better answer doesn't come before it expires. !!! – varunkr Sep 16 '16 at 21:06