code: 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);
      }
docs: 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.