1

I have a broadcast receiver that listens for power connection events. Whenever the device is connected to power, I attempt to transfer files from the APP to a Server in a machine running Ubuntu. The files are transferred over Bluetooth. Since the transfer of files is important, if for any reason the transfer has an error, or the connection is not successful in a first attempt, I retry it up to 6 times allowing 3 minutes between attempt.

In the beginning, I was using an asynctask which was simply maintained alive as long as we still have retries available and the file transfer has not been successfully done. I read, that having an asynctask in a broadcast receiver is not a good practice which makes total sense, especially since I'm forcing the task to run for long periods of time. Therefore, I decided to change to a JobIntentService such that every time a power connection event was captured by the receiver, I would issue the job that will transfer files to my computer. Within the job, right after the file transfer is finished or failed, I would set an alarm that will send a pending intent to the broadcast and call the job again.

I was running this and I have noticed that (as different from before) I've gotten too many "Connection reset by peer" errors during the transfer, which makes me wonder if the Job is being stopped before its completed or something like that?. Those errors used not to happen in my previous implementation. Then, I also noticed that for some reason the OS seems to have launched the JobIntentService again by itself (there was no event that launched it) which caused inconsistencies on my code and caused me to lose some files (I'm not supposed to allow multiple instances of this job running at the same time)

My question is, why do you think the service was restarted? is it possible for the JobIntentService to be finished and restarted by the OS during the BT transfer? The files are heavy so they take several minutes to transfer from the app to the machine. I was thinking of trying a foreground service instead of the JobIntent and having a notification for the service or going back to my previous implementation.

Any suggestions?

This is how I call the Intent Job.

FileTransferJob.isJobAlreadyRunning = true;
Intent intent = new Intent(context, FileTransferJob.class);
intent.putExtra(TRANSFER_DATA_RETRIES, retries);
FileTransferJob.enqueueWork(context,intent);

This is the JobIntentService class

public class FileTransferJob extends JobIntentService {
/**
 * Unique job ID for this service.
 */
public static boolean isJobAlreadyRunning = false; //This flag will remain true as soon as this JOB is called and as long as retries are still available
public static final int JOB_ID = 1000;
public static int MAX_NUM_OF_RETRIES = 6;//How many times are we going to retry to send the data
private int MINUTES_TO_WAIT = 3; //The minutes we wait between each attempt
public String TAG = "FileTransferJob";

/**
 * Convenience method for enqueuing work in to this service.
 */
public static void enqueueWork(Context context, Intent work) {
    enqueueWork(context, FileTransferJob.class, JOB_ID, work);
}

@Override
protected void onHandleWork(Intent intent) {

    int retriesRemaining = intent.getIntExtra(TRANSFER_DATA_RETRIES,1); //Get the number of retries we have. Default to 1 (this one)
    Log.d(TAG, "onHandleWork: About to attempt transfer with remaining retries " + String.valueOf(retriesRemaining));


    try {
        BluetoothFileTransfer btio = new BluetoothFileTransfer();
        Log.d(TAG, "onHandleWork: About to send data over Bluetooth");
        btio.sendData(FileTransferJob.this.getApplicationContext());
        FileTransferJob.isJobAlreadyRunning = false; //Success, then this is no longer running
        Log.d(TAG, "onHandleWork: The data has been sent over Bluetooth");
    }catch (Exception e){
        Log.d(TAG, "onHandleWork: There was a problem with the BT transfer: " + e.getMessage());

        retriesRemaining--; //We reduce the number of retries we have

        //If no more retries available, simply do nothing
        if (retriesRemaining > 0) {
            Log.d(TAG, "onHandleWork: Setting up alarm. Retries ramaining: " + String.valueOf(retriesRemaining));
            AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
            Intent alarmIntent = new Intent(this.getApplicationContext(), DataCollectReceiver.class);
            alarmIntent.setAction(TRANSFER_DATA);
            alarmIntent.putExtra(TRANSFER_DATA_RETRIES, retriesRemaining);

            PendingIntent alarmPendingIntent = PendingIntent.getBroadcast( this.getApplicationContext(), PENDING_INTENT_CODE_FILE_TRANSFER_JOB, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            int totalTime = MINUTES_TO_WAIT*60*1000;
            if(alarmManager != null){
                alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
                        System.currentTimeMillis() + totalTime,
                        alarmPendingIntent);
                Log.d(TAG, "onHandleWork: Alarm is set, waiting " + String.valueOf(totalTime) + " minutes for next attempt...");
            }else{
                Log.d(TAG, "onHandleWork: Alarm could not be set. Alarm manager is NULL");
            }

        }else{
            Log.d(TAG, "onHandleWork: There are no more retries");
            FileTransferJob.isJobAlreadyRunning = false;
        }
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy: The file transfer JOB has finished");
}

}

The logcat. The highlighted section shows what I believe is the OS creating a new instance of the JobService and running it.

enter image description here

Roger
  • 579
  • 4
  • 13
  • Your problem can be solved by WorkManager. Have you tried using WorkManager instead? You can refer to my answers on [SO](https://stackoverflow.com/questions/50343578/android-work-manager-vs-services/50373395#50373395),[SO](https://stackoverflow.com/questions/50943056/avoiding-duplicating-periodicworkrequest-from-workmanager/50943231#50943231) & [SO](https://stackoverflow.com/questions/50363541/schedule-a-work-on-a-specific-time-with-workmanager/50363613#50363613) – Sagar Jun 28 '18 at 00:56
  • Is the service restarted or it seems to be restarted? Be precise, please. And please don's ask so many questions in one question. Again, be precise - otherwise nobody will answer. – Marian Paździoch Sep 05 '18 at 10:00
  • @Roger, have you found a fix for this? I've encountered similar behaviour in my app when starting a JobIntentService to download files from server. It will just restart and duplicate download after 10 minutes, with the previous download still running. – Trancol Apr 07 '21 at 08:43

1 Answers1

1

Let me try to answer it as i have noticed this behavior. The JobIntentService/JobService/Worker will run only for 10 mins after that they will be stopped and you can get a call back on onStopJob/onStopCurrentWork in case of JobService/JobIntentService and OnStopped in case of Worker.

Though the android document has explained this behavior for Worker only but JobService/JobIntentServie both behaves the same way

A Worker is given a maximum of ten minutes to finish its execution and return a ListenableWorker.Result. After this time has expired, the Worker will be signalled to stop.

Hence i can assume that your task is not finished within 10 mins and Android is destroying the JobIntentService. Now the thing is that All of these Jobservice/JobIntentService/Worker are started again (If stopped prematurely) after the exponential backoff time i.e. 30secs , 1 min, 2 mins,4 mins...

Although the weird part is that the old thread which died after running 10 mins started as explained but as the call back comes again on HandleWork it starts another thread again which duplicates the work done by the thread and that is why i think you see inconsistencies.

The suggestion is that you break your work in such a way that can be finished withing the 10 mins window. Or We can wait for Google team to fix this.

anshul
  • 982
  • 1
  • 11
  • 33
  • Do you know of a fix for this? Unfortunately, my service can't finish the download work in 10 minutes because it's largely dependent on the server and connection speed as well. – Trancol Apr 07 '21 at 08:46