jobscheduler/src/main/java/me/tatarka/support/internal/job/JobSchedulerService.java
private JobStatus rescheduleFailedJob(JobStatus job) {
        if (job.hasIdleConstraint()) {
            // Don't need to modify time on idle job, it will run whenever the next idle period is.
            return job;
        }
        
        final long elapsedNowMillis = SystemClock.elapsedRealtime();
        final JobInfo jobInfo = job.getJob();

        final long initialBackoffMillis = jobInfo.getInitialBackoffMillis();
        final int backoffAttemps = job.getNumFailures() + 1;

        long delayMillis;
        switch (job.getJob().getBackoffPolicy()) {
            case JobInfo.BACKOFF_POLICY_LINEAR:
                delayMillis = initialBackoffMillis * backoffAttemps;
                break;
            default:
            case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
                delayMillis = (long) Math.scalb(initialBackoffMillis, backoffAttemps - 1);
                break;
        }
        delayMillis = Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
        return new JobStatus(job, elapsedNowMillis + delayMillis, JobStatus.NO_LATEST_RUNTIME, backoffAttemps);
    }
private JobStatus rescheduleFailedJob(JobStatus job) {
        if (job.hasIdleConstraint()) {
            // Don't need to modify time on idle job, it will run whenever the next idle period is.
            return job;
        }
        
        final long elapsedNowMillis = SystemClock.elapsedRealtime();
        final JobInfo jobInfo = job.getJob();

        final long initialBackoffMillis = jobInfo.getInitialBackoffMillis();
        final int backoffAttemps = job.getNumFailures() + 1;

        long delayMillis;
        switch (job.getJob().getBackoffPolicy()) {
            case JobInfo.BACKOFF_POLICY_LINEAR:
                delayMillis = initialBackoffMillis * backoffAttemps;
                break;
            default:
            case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
                delayMillis = (long) Math.scalb(initialBackoffMillis, backoffAttemps - 1);
                break;
        }
        delayMillis = Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
        return new JobStatus(job, elapsedNowMillis + delayMillis, JobStatus.NO_LATEST_RUNTIME, backoffAttemps);
    }
A job is rescheduled with exponential back-off if the client requests this from their
execution logic.
A caveat is for idle-mode jobs, for which the idle-mode constraint will usurp the
timeliness of the reschedule. For an idle-mode job, no deadline is given.
@return A newly instantiated JobStatus with the same constraints as the last job except
with adjusted timing constraints.