Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crashed service restarted after a very long time

Tags:

android

I am running a service in the foreground. Sometimes it is terminated, presumably for memory reasons (although I'm not 100% sure of that from the LogCat log). Other services that are terminated are scheduled for a restart in 5000ms, but looking at the log, the restarts of my service are very long, for example:

11-15 15:39:48.756: W/ActivityManager(375): Scheduling restart of crashed service com.example.app/com.example.SensorService in 1019562ms

What could account for this? How is the restart interval set? I have seen some suggestions that services with notifications are restarted with a shorter delay, but my service does have a notification.

like image 816
Catherine Avatar asked Nov 16 '13 00:11

Catherine


3 Answers

From com/android/server/am/ActiveServices.java (not exposed)

// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;

// How long a service needs to be running until restarting its process
// is no longer considered to be a relaunch of the service.
static final int SERVICE_RESTART_DURATION = 5*1000;

// How long a service needs to be running until it will start back at
// SERVICE_RESTART_DURATION after being killed.
static final int SERVICE_RESET_RUN_DURATION = 60*1000;

// Multiplying factor to increase restart duration time by, for each time
// a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
static final int SERVICE_RESTART_DURATION_FACTOR = 4;

// The minimum amount of time between restarting services that we allow.
// That is, when multiple services are restarting, we won't allow each
// to restart less than this amount of time from the last one.
static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;

// Maximum amount of time for there to be no activity on a service before
// we consider it non-essential and allow its process to go on the
// LRU background list.
static final int MAX_SERVICE_INACTIVITY = 30*60*1000;

What's happening for you probably is your service is dying quicker then SERVICE_RESET_RUN_DURATION and then restart time is multiplied by SERVICE_RESTART_DURATION_FACTOR.

Starting from line #881:

            // If it has been a "reasonably long time" since the service
            // was started, then reset our restart duration back to
            // the beginning, so we don't infinitely increase the duration
            // on a service that just occasionally gets killed (which is
            // a normal case, due to process being killed to reclaim memory).
            if (now > (r.restartTime+resetTime)) {
                r.restartCount = 1;
                r.restartDelay = minDuration;
            } else {
                if ((r.serviceInfo.applicationInfo.flags
                        &ApplicationInfo.FLAG_PERSISTENT) != 0) {
                    // Services in peristent processes will restart much more
                    // quickly, since they are pretty important.  (Think SystemUI).
                    r.restartDelay += minDuration/2;
                } else {
                    r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
                    if (r.restartDelay < minDuration) {
                        r.restartDelay = minDuration;
                    }
                }
            }

Line below does the backing off your service.

r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;

So you should fix the case if your service is dying before running for SERVICE_RESET_RUN_DURATION.

like image 123
auselen Avatar answered Nov 19 '22 09:11

auselen


First of all I think you will call the Service class from an Activity class or from any BroadCastReceiver class.

You would like to start the service after some specific or may be after 5000ms . Though your question is not clear for me. Still as per my knowledge you have to call the service from your service class. For example:

    public class UpdateWidgetServiceDemo extends Service {

      public static int numberOfItems=0;
      String resultURL="";

        //numberOfItems=0;
        private static  String LOG = "testwidgets";

        ArrayList<String> feedsPubDate;

          @TargetApi(Build.VERSION_CODES.GINGERBREAD)
        @SuppressWarnings("deprecation")
        @Override
          public void onStart(Intent intent, int startId) {

              StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
              StrictMode.setThreadPolicy(policy);
              Log.i(LOG, "Called");
            // Create some random data

            feedsPubDate=new ArrayList<String>(); 

            /////////////////////////////////////////////////////////////////////

    //        SharedPreferences sp = getSharedPreferences("updateOptions", 0);
    //        int updatePeriod=sp.getInt("UpdatePeriod", -1);

            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.SECOND, 10);

            Intent intent1 = new Intent(this, UpdateWidgetServiceDemo.class);

            PendingIntent pintent = PendingIntent.getService(this, 0, intent1, 0);

            AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
            int i;
            i=15;
            alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),  i* 1000, pintent);
}
.
.
.

Here the main important part is :

Calendar cal = Calendar.getInstance();
                cal.add(Calendar.SECOND, 10);

                Intent intent1 = new Intent(this, UpdateWidgetServiceDemo.class);

                PendingIntent pintent = PendingIntent.getService(this, 0, intent1, 0);

                AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
                int i;
                i=15;
                alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),  i* 1000, pintent);

I think your problem will be solved.

Enjoy!!!

like image 23
Satyaki Mukherjee Avatar answered Nov 19 '22 08:11

Satyaki Mukherjee


You can set the update interval using method below, Service will be restarted every 1 minute.:

void setServiceIntervalAlarm()
{
    // set alarm for next 60 seconds
    Intent updateIntent = new Intent();
    updateIntent.setClass(this, CheckOutRequestsService.class);

    PendingIntent pendingIntent = PendingIntent.getService(this, 23, updateIntent, 0);
    // Schedule alarm, and force the device awake for this update
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    long nextUpdate = 60000;
    alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), nextUpdate, pendingIntent);
}
like image 1
Vinay Avatar answered Nov 19 '22 08:11

Vinay