@Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) { dumpImpl(writer); }
@Override public void onCreate() { super.onCreate(); handlerThread.start(); handlerFuture.set(new Handler(handlerThread.getLooper())); }
/** Calls {@link #onStopJob(JobParameters)}. Should only be run on the main thread. */ @MainThread private void callOnStopJobImpl( JobCallback jobCallback, boolean needToSendResult, @JobResult int terminatingResult) { boolean shouldRetry = onStopJob(jobCallback.job); if (needToSendResult) { backgroundExecutor.execute( UnitOfWork.finishJobWithResult( jobCallback, shouldRetry ? RESULT_FAIL_RETRY : terminatingResult)); } }
@Test public void testOnStartCommand_handlesStartJob_noCallback() { JobService service = spy(new ExampleJobService()); int startId = 7; Intent executeJobIntent = new Intent(JobService.ACTION_EXECUTE); executeJobIntent.putExtra("tag", "foobar"); service.onStartCommand(executeJobIntent, 0, startId); verify(service).stopSelf(startId); }
@Test public void stop_noCallback_finished() throws Exception { JobService service = spy(new StoppableJobService(/* shouldReschedule= */ false)); JobInvocation job = new Builder() .setTag("Tag") .setTrigger(Trigger.NOW) .setService(StoppableJobService.class.getName()) .build(); IRemoteJobService.Stub.asInterface(service.onBind(null)) .stop(getJobCoder().encode(job, new Bundle()), true); flush(service); verify(service, never()).onStopJob(job); }
private static void verifyOnUnbindCausesResult(JobService service, int expectedResult) throws Exception { Job jobSpec = TestUtil.getBuilderWithNoopValidator() .setTag("tag") .setService(service.getClass()) .setTrigger(Trigger.NOW) .build(); Bundle jobSpecData = getJobCoder().encode(jobSpec, new Bundle()); FutureSettingJobCallback callback = new FutureSettingJobCallback(); // start the service IRemoteJobService.Stub.asInterface(service.onBind(null)).start(jobSpecData, callback); // shouldn't have sent a result message yet (still doing background work) assertFalse(callback.getJobFinishedFuture().isDone()); // manually trigger the onUnbind hook service.onUnbind(new Intent()); flush(service); callback.verifyCalledWithJobAndResult(jobSpec, expectedResult); // Calling jobFinished should not attempt to send a second message callback.reset(); service.jobFinished(jobSpec, false); assertFalse(callback.getJobFinishedFuture().isDone()); }
@Override @MainThread public final int onStartCommand(Intent intent, int flags, int startId) { stopSelf(startId); return START_NOT_STICKY; }
IRemoteJobService.Stub.asInterface(service.onBind(null)).start(jobSpecData, noopCallback);
/** Calls {@link #onStartJob(JobParameters)}. Should only be run on the main thread. */ @MainThread private void callOnStartJobImpl(JobParameters jobParameters) { boolean moreWork = onStartJob(jobParameters); if (!moreWork) { // If there's no more work to do, we're done. Report success. backgroundExecutor.execute( UnitOfWork.removeAndFinishJobWithResult( this, jobParameters, /* result= */ RESULT_SUCCESS)); } }
@Override public void onDestroy() { super.onDestroy(); App.unregister(this); }
@Test public void testOnStartCommand_handlesEmptyAction() { JobService service = spy(new ExampleJobService()); int startId = 7; Intent emptyActionIntent = new Intent(""); service.onStartCommand(emptyActionIntent, 0, startId); verify(service).stopSelf(startId); }
@Test public void testOnStartCommand_handlesStartJob_validRequest() throws Exception { JobService service = spy(new ExampleJobService()); Job jobSpec = TestUtil.getBuilderWithNoopValidator() .setTag("tag") .setService(ExampleJobService.class) .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) .setTrigger(Trigger.NOW) .setLifetime(Lifetime.FOREVER) .build(); countDownLatch = new CountDownLatch(1); Bundle jobSpecData = getJobCoder().encode(jobSpec, new Bundle()); IRemoteJobService remoteJobService = IRemoteJobService.Stub.asInterface(service.onBind(new Intent(JobService.ACTION_EXECUTE))); remoteJobService.start(jobSpecData, noopCallback); flush(service); assertTrue("Expected job to run to completion", countDownLatch.await(5, TimeUnit.SECONDS)); }
@Test public void testOnStartCommand_handlesUnknownAction() { JobService service = spy(new ExampleJobService()); int startId = 7; Intent emptyActionIntent = new Intent("foo.bar.baz"); service.onStartCommand(emptyActionIntent, 0, startId); verify(service).stopSelf(startId); }
private static String dump(JobService service) throws Exception { StringWriter sw = new StringWriter(); service.dumpImpl(new PrintWriter(sw)); return sw.toString(); }
@Override public void onCreate() { super.onCreate(); App.register(this); }
@Test public void onStartJob_jobFinishedNotReschedule() throws Exception { // Verify that a termination request from within onStartJob will cause the result to be sent // to the bouncer service's handler, regardless of what value is ultimately returned from // onStartJob. JobService reschedulingService = new JobService() { @Override public boolean onStartJob(@NonNull JobParameters job) { jobFinished(job, false /* don't retry this job */); return false; } @Override public boolean onStopJob(@NonNull JobParameters job) { return false; } }; Job jobSpec = TestUtil.getBuilderWithNoopValidator() .setTag("tag") .setService(reschedulingService.getClass()) .setTrigger(Trigger.NOW) .build(); FutureSettingJobCallback callback = new FutureSettingJobCallback(); IRemoteJobService.Stub.asInterface(reschedulingService.onBind(null)) .start(getJobCoder().encode(jobSpec, new Bundle()), callback); flush(reschedulingService); callback.verifyCalledWithJobAndResult(jobSpec, JobService.RESULT_SUCCESS); }
@Test public void testOnStartCommand_handlesNullAction() { JobService service = spy(new ExampleJobService()); int startId = 7; Intent nullActionIntent = new Intent(); service.onStartCommand(nullActionIntent, 0, startId); verify(service).stopSelf(startId); }
@Test public void onStartJob_jobFinishedReschedule() throws Exception { // Verify that a retry request from within onStartJob will cause the retry result to be sent // to the bouncer service's handler, regardless of what value is ultimately returned from // onStartJob. JobService reschedulingService = new JobService() { @Override public boolean onStartJob(@NonNull JobParameters job) { // Reschedules job. jobFinished(job, true /* retry this job */); return false; } @Override public boolean onStopJob(@NonNull JobParameters job) { return false; } }; Job jobSpec = TestUtil.getBuilderWithNoopValidator() .setTag("tag") .setService(reschedulingService.getClass()) .setTrigger(Trigger.NOW) .build(); FutureSettingJobCallback callback = new FutureSettingJobCallback(); IRemoteJobService.Stub.asInterface(reschedulingService.onBind(null)) .start(getJobCoder().encode(jobSpec, new Bundle()), callback); flush(reschedulingService); callback.verifyCalledWithJobAndResult(jobSpec, JobService.RESULT_FAIL_RETRY); }
@Test public void testOnStartCommand_handlesStartJob_nullData() { JobService service = spy(new ExampleJobService()); int startId = 7; Intent executeJobIntent = new Intent(JobService.ACTION_EXECUTE); service.onStartCommand(executeJobIntent, 0, startId); verify(service).stopSelf(startId); }
@Test public void testOnStartCommand_handlesNullIntent() { JobService service = spy(new ExampleJobService()); int startId = 7; try { service.onStartCommand(null, 0, startId); verify(service).stopSelf(startId); } catch (NullPointerException npe) { fail("Unexpected NullPointerException after calling onStartCommand with a null Intent."); } }