private static Bundle encodeJob(JobParameters job) { return getJobCoder().encode(job, new Bundle()); }
void sendResult(@JobResult int result) { try { remoteCallback.jobFinished(getJobCoder().encode(job, new Bundle()), result); } catch (RemoteException remoteException) { Log.e(TAG, "Failed to send result to driver", remoteException); } } }
private void handleStopMessage(Message message) { Builder builder = GooglePlayReceiver.getJobCoder().decode(message.getData()); if (builder == null) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Invalid stop execution message."); } return; } JobInvocation job = builder.build(); ExecutionDelegator.stopJob(job, true); } }
@Override @BinderThread public void stop(Bundle invocationData, boolean needToSendResult) { JobInvocation.Builder invocation = getJobCoder().decode(invocationData); if (invocation == null) { Log.wtf(TAG, "stop: unknown invocation provided"); return; } JobService.this.handleStopJobRequest(invocation.build(), needToSendResult); } };
@Override public void jobFinished(Bundle invocationData, @JobService.JobResult int result) { JobInvocation.Builder invocation = getJobCoder().decode(invocationData); if (invocation == null) { Log.wtf(TAG, "jobFinished: unknown invocation provided"); return; } ExecutionDelegator.this.onJobFinishedMessage(invocation.build(), result); } };
@Override @BinderThread public void start(Bundle invocationData, IJobCallback callback) { JobInvocation.Builder invocation = getJobCoder().decode(invocationData); if (invocation == null) { Log.wtf(TAG, "start: unknown invocation provided"); return; } JobService.this.handleStartJobRequest(invocation.build(), callback); }
@Override public void start(Bundle invocationData, IJobCallback callback) { jobParametersAtomicReference.set( GooglePlayReceiver.getJobCoder().decode(invocationData).build()); }
Message message = Message.obtain(); message.what = GooglePlayMessageHandler.MSG_STOP_EXEC; JobCoder jobCoder = GooglePlayReceiver.getJobCoder(); Bundle data = TestUtil.encodeContentUriJob(TestUtil.getContentUriTrigger(), jobCoder); JobInvocation jobInvocation = jobCoder.decode(data).build();
@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); }
.build(); final Bundle jobSpecData = getJobCoder().encode(jobSpec, new Bundle()); IRemoteJobService.Stub.asInterface(service.onBind(null)).start(jobSpecData, noopCallback);
@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)); }
void verifyCalledWithJobAndResult(JobParameters job, int result) throws Exception { Pair<Bundle, Integer> jobFinishedResult = getJobFinishedFuture().get(TIMEOUT_MS, TimeUnit.MILLISECONDS); assertNotNull(jobFinishedResult); JobCoder jc = getJobCoder(); assertEquals( // re-encode so they're the same class jc.decode(jc.encode(job, new Bundle())).build(), jc.decode(jobFinishedResult.first).build()); assertEquals(result, (int) jobFinishedResult.second); }
@Test public void stop_withCallback_done() throws Exception { StoppableJobService service = spy(new StoppableJobService(/* shouldReschedule= */ true)); JobInvocation job = new Builder() .setTag("Tag") .setTrigger(Trigger.NOW) .setService(StoppableJobService.class.getName()) .build(); Bundle jobSpecData = getJobCoder().encode(job, new Bundle()); FutureSettingJobCallback callback = new FutureSettingJobCallback(); IRemoteJobService.Stub.asInterface(service.onBind(null)).start(jobSpecData, callback); IRemoteJobService.Stub.asInterface(service.onBind(null)).stop(jobSpecData, true); flush(service); assertEquals(1, service.getNumberOfStopRequestsReceived()); callback.verifyCalledWithJobAndResult(job, JobService.RESULT_FAIL_RETRY); }
@Test public void stop_withCallback_retry() throws Exception { StoppableJobService service = spy(new StoppableJobService(/* shouldReschedule= */ false)); JobInvocation job = new Builder() .setTag("Tag") .setTrigger(Trigger.NOW) .setService(StoppableJobService.class.getName()) .build(); Bundle jobSpecData = getJobCoder().encode(job, new Bundle()); FutureSettingJobCallback callback = new FutureSettingJobCallback(); // start the service IRemoteJobService.Stub.asInterface(service.onBind(null)).start(jobSpecData, callback); IRemoteJobService.Stub.asInterface(service.onBind(null)).stop(jobSpecData, true); flush(service); assertEquals(1, service.getNumberOfStopRequestsReceived()); callback.verifyCalledWithJobAndResult(job, JobService.RESULT_SUCCESS); }
@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 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); }
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()); }
@Test public void testOnStartCommand_handlesStartJob_doNotStartRunningJobAgain() throws Exception { StoppableJobService service = new StoppableJobService(/* shouldReschedule= */ false); Job jobSpec = TestUtil.getBuilderWithNoopValidator() .setTag("tag") .setService(StoppableJobService.class) .setTrigger(Trigger.NOW) .build(); Bundle jobSpecData = getJobCoder().encode(jobSpec, new Bundle()); IRemoteJobService.Stub.asInterface(service.onBind(null)).start(jobSpecData, null); IRemoteJobService.Stub.asInterface(service.onBind(null)).start(jobSpecData, null); flush(service); assertEquals(1, service.getNumberOfStartRequestsReceived()); }