1*b7c941bbSAndroid Build Coastguard Worker /* 2*b7c941bbSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project 3*b7c941bbSAndroid Build Coastguard Worker * 4*b7c941bbSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*b7c941bbSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*b7c941bbSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*b7c941bbSAndroid Build Coastguard Worker * 8*b7c941bbSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*b7c941bbSAndroid Build Coastguard Worker * 10*b7c941bbSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*b7c941bbSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*b7c941bbSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*b7c941bbSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*b7c941bbSAndroid Build Coastguard Worker * limitations under the License. 15*b7c941bbSAndroid Build Coastguard Worker */ 16*b7c941bbSAndroid Build Coastguard Worker 17*b7c941bbSAndroid Build Coastguard Worker package android.jobscheduler; 18*b7c941bbSAndroid Build Coastguard Worker 19*b7c941bbSAndroid Build Coastguard Worker import android.annotation.TargetApi; 20*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobInfo; 21*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobParameters; 22*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobScheduler; 23*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobService; 24*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobWorkItem; 25*b7c941bbSAndroid Build Coastguard Worker import android.content.ClipData; 26*b7c941bbSAndroid Build Coastguard Worker import android.content.Context; 27*b7c941bbSAndroid Build Coastguard Worker import android.content.Intent; 28*b7c941bbSAndroid Build Coastguard Worker import android.content.pm.PackageManager; 29*b7c941bbSAndroid Build Coastguard Worker import android.net.Uri; 30*b7c941bbSAndroid Build Coastguard Worker import android.os.Process; 31*b7c941bbSAndroid Build Coastguard Worker import android.util.Log; 32*b7c941bbSAndroid Build Coastguard Worker 33*b7c941bbSAndroid Build Coastguard Worker import junit.framework.Assert; 34*b7c941bbSAndroid Build Coastguard Worker 35*b7c941bbSAndroid Build Coastguard Worker import java.util.ArrayList; 36*b7c941bbSAndroid Build Coastguard Worker import java.util.concurrent.CountDownLatch; 37*b7c941bbSAndroid Build Coastguard Worker import java.util.concurrent.TimeUnit; 38*b7c941bbSAndroid Build Coastguard Worker 39*b7c941bbSAndroid Build Coastguard Worker /** 40*b7c941bbSAndroid Build Coastguard Worker * Handles callback from the framework {@link android.app.job.JobScheduler}. The behaviour of this 41*b7c941bbSAndroid Build Coastguard Worker * class is configured through the static 42*b7c941bbSAndroid Build Coastguard Worker * {@link TestEnvironment}. 43*b7c941bbSAndroid Build Coastguard Worker */ 44*b7c941bbSAndroid Build Coastguard Worker @TargetApi(21) 45*b7c941bbSAndroid Build Coastguard Worker public class MockJobService extends JobService { 46*b7c941bbSAndroid Build Coastguard Worker private static final String TAG = "MockJobService"; 47*b7c941bbSAndroid Build Coastguard Worker 48*b7c941bbSAndroid Build Coastguard Worker /** Wait this long before timing out the test. */ 49*b7c941bbSAndroid Build Coastguard Worker private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds. 50*b7c941bbSAndroid Build Coastguard Worker 51*b7c941bbSAndroid Build Coastguard Worker private JobParameters mParams; 52*b7c941bbSAndroid Build Coastguard Worker 53*b7c941bbSAndroid Build Coastguard Worker ArrayList<JobWorkItem> mReceivedWork = new ArrayList<>(); 54*b7c941bbSAndroid Build Coastguard Worker 55*b7c941bbSAndroid Build Coastguard Worker ArrayList<JobWorkItem> mPendingCompletions = new ArrayList<>(); 56*b7c941bbSAndroid Build Coastguard Worker 57*b7c941bbSAndroid Build Coastguard Worker private boolean mWaitingForStop; 58*b7c941bbSAndroid Build Coastguard Worker 59*b7c941bbSAndroid Build Coastguard Worker @Override onDestroy()60*b7c941bbSAndroid Build Coastguard Worker public void onDestroy() { 61*b7c941bbSAndroid Build Coastguard Worker super.onDestroy(); 62*b7c941bbSAndroid Build Coastguard Worker Log.i(TAG, "Destroying test service"); 63*b7c941bbSAndroid Build Coastguard Worker if (TestEnvironment.getTestEnvironment().getExpectedWork() != null) { 64*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(mParams, 0, 0, mReceivedWork, 65*b7c941bbSAndroid Build Coastguard Worker null); 66*b7c941bbSAndroid Build Coastguard Worker } 67*b7c941bbSAndroid Build Coastguard Worker } 68*b7c941bbSAndroid Build Coastguard Worker 69*b7c941bbSAndroid Build Coastguard Worker @Override onCreate()70*b7c941bbSAndroid Build Coastguard Worker public void onCreate() { 71*b7c941bbSAndroid Build Coastguard Worker super.onCreate(); 72*b7c941bbSAndroid Build Coastguard Worker Log.i(TAG, "Created test service."); 73*b7c941bbSAndroid Build Coastguard Worker } 74*b7c941bbSAndroid Build Coastguard Worker 75*b7c941bbSAndroid Build Coastguard Worker @Override onStartJob(JobParameters params)76*b7c941bbSAndroid Build Coastguard Worker public boolean onStartJob(JobParameters params) { 77*b7c941bbSAndroid Build Coastguard Worker Log.i(TAG, "Test job executing: " + params.getJobId()); 78*b7c941bbSAndroid Build Coastguard Worker mParams = params; 79*b7c941bbSAndroid Build Coastguard Worker 80*b7c941bbSAndroid Build Coastguard Worker int permCheckRead = PackageManager.PERMISSION_DENIED; 81*b7c941bbSAndroid Build Coastguard Worker int permCheckWrite = PackageManager.PERMISSION_DENIED; 82*b7c941bbSAndroid Build Coastguard Worker ClipData clip = params.getClipData(); 83*b7c941bbSAndroid Build Coastguard Worker if (clip != null) { 84*b7c941bbSAndroid Build Coastguard Worker permCheckRead = checkUriPermission(clip.getItemAt(0).getUri(), Process.myPid(), 85*b7c941bbSAndroid Build Coastguard Worker Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION); 86*b7c941bbSAndroid Build Coastguard Worker permCheckWrite = checkUriPermission(clip.getItemAt(0).getUri(), Process.myPid(), 87*b7c941bbSAndroid Build Coastguard Worker Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 88*b7c941bbSAndroid Build Coastguard Worker } 89*b7c941bbSAndroid Build Coastguard Worker 90*b7c941bbSAndroid Build Coastguard Worker TestWorkItem[] expectedWork = TestEnvironment.getTestEnvironment().getExpectedWork(); 91*b7c941bbSAndroid Build Coastguard Worker if (expectedWork != null) { 92*b7c941bbSAndroid Build Coastguard Worker try { 93*b7c941bbSAndroid Build Coastguard Worker if (!TestEnvironment.getTestEnvironment().awaitDoWork()) { 94*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead, 95*b7c941bbSAndroid Build Coastguard Worker permCheckWrite, null, "Spent too long waiting to start executing work"); 96*b7c941bbSAndroid Build Coastguard Worker return false; 97*b7c941bbSAndroid Build Coastguard Worker } 98*b7c941bbSAndroid Build Coastguard Worker } catch (InterruptedException e) { 99*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead, 100*b7c941bbSAndroid Build Coastguard Worker permCheckWrite, null, "Failed waiting for work: " + e); 101*b7c941bbSAndroid Build Coastguard Worker return false; 102*b7c941bbSAndroid Build Coastguard Worker } 103*b7c941bbSAndroid Build Coastguard Worker JobWorkItem work; 104*b7c941bbSAndroid Build Coastguard Worker int index = 0; 105*b7c941bbSAndroid Build Coastguard Worker while ((work = params.dequeueWork()) != null) { 106*b7c941bbSAndroid Build Coastguard Worker final Intent intent = work.getIntent(); 107*b7c941bbSAndroid Build Coastguard Worker Log.i(TAG, "Received work #" + index + ": " + intent); 108*b7c941bbSAndroid Build Coastguard Worker mReceivedWork.add(work); 109*b7c941bbSAndroid Build Coastguard Worker 110*b7c941bbSAndroid Build Coastguard Worker int flags = 0; 111*b7c941bbSAndroid Build Coastguard Worker 112*b7c941bbSAndroid Build Coastguard Worker if (index < expectedWork.length) { 113*b7c941bbSAndroid Build Coastguard Worker TestWorkItem expected = expectedWork[index]; 114*b7c941bbSAndroid Build Coastguard Worker int grantFlags = intent == null ? 0 : intent.getFlags(); 115*b7c941bbSAndroid Build Coastguard Worker if (expected.requireUrisGranted != null) { 116*b7c941bbSAndroid Build Coastguard Worker for (int ui = 0; ui < expected.requireUrisGranted.length; ui++) { 117*b7c941bbSAndroid Build Coastguard Worker if ((grantFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { 118*b7c941bbSAndroid Build Coastguard Worker if (checkUriPermission(expected.requireUrisGranted[ui], 119*b7c941bbSAndroid Build Coastguard Worker Process.myPid(), Process.myUid(), 120*b7c941bbSAndroid Build Coastguard Worker Intent.FLAG_GRANT_READ_URI_PERMISSION) 121*b7c941bbSAndroid Build Coastguard Worker != PackageManager.PERMISSION_GRANTED) { 122*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, 123*b7c941bbSAndroid Build Coastguard Worker permCheckRead, permCheckWrite, null, 124*b7c941bbSAndroid Build Coastguard Worker "Expected read permission but not granted: " 125*b7c941bbSAndroid Build Coastguard Worker + expected.requireUrisGranted[ui] 126*b7c941bbSAndroid Build Coastguard Worker + " @ #" + index); 127*b7c941bbSAndroid Build Coastguard Worker return false; 128*b7c941bbSAndroid Build Coastguard Worker } 129*b7c941bbSAndroid Build Coastguard Worker } 130*b7c941bbSAndroid Build Coastguard Worker if ((grantFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { 131*b7c941bbSAndroid Build Coastguard Worker if (checkUriPermission(expected.requireUrisGranted[ui], 132*b7c941bbSAndroid Build Coastguard Worker Process.myPid(), Process.myUid(), 133*b7c941bbSAndroid Build Coastguard Worker Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 134*b7c941bbSAndroid Build Coastguard Worker != PackageManager.PERMISSION_GRANTED) { 135*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, 136*b7c941bbSAndroid Build Coastguard Worker permCheckRead, permCheckWrite, null, 137*b7c941bbSAndroid Build Coastguard Worker "Expected write permission but not granted: " 138*b7c941bbSAndroid Build Coastguard Worker + expected.requireUrisGranted[ui] 139*b7c941bbSAndroid Build Coastguard Worker + " @ #" + index); 140*b7c941bbSAndroid Build Coastguard Worker return false; 141*b7c941bbSAndroid Build Coastguard Worker } 142*b7c941bbSAndroid Build Coastguard Worker } 143*b7c941bbSAndroid Build Coastguard Worker } 144*b7c941bbSAndroid Build Coastguard Worker } 145*b7c941bbSAndroid Build Coastguard Worker if (expected.requireUrisNotGranted != null) { 146*b7c941bbSAndroid Build Coastguard Worker // XXX note no delay here, current impl will have fully revoked the 147*b7c941bbSAndroid Build Coastguard Worker // permission by the time we return from completing the last work. 148*b7c941bbSAndroid Build Coastguard Worker for (int ui = 0; ui < expected.requireUrisNotGranted.length; ui++) { 149*b7c941bbSAndroid Build Coastguard Worker if ((grantFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { 150*b7c941bbSAndroid Build Coastguard Worker if (checkUriPermission(expected.requireUrisNotGranted[ui], 151*b7c941bbSAndroid Build Coastguard Worker Process.myPid(), Process.myUid(), 152*b7c941bbSAndroid Build Coastguard Worker Intent.FLAG_GRANT_READ_URI_PERMISSION) 153*b7c941bbSAndroid Build Coastguard Worker != PackageManager.PERMISSION_DENIED) { 154*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, 155*b7c941bbSAndroid Build Coastguard Worker permCheckRead, permCheckWrite, null, 156*b7c941bbSAndroid Build Coastguard Worker "Not expected read permission but granted: " 157*b7c941bbSAndroid Build Coastguard Worker + expected.requireUrisNotGranted[ui] 158*b7c941bbSAndroid Build Coastguard Worker + " @ #" + index); 159*b7c941bbSAndroid Build Coastguard Worker return false; 160*b7c941bbSAndroid Build Coastguard Worker } 161*b7c941bbSAndroid Build Coastguard Worker } 162*b7c941bbSAndroid Build Coastguard Worker if ((grantFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { 163*b7c941bbSAndroid Build Coastguard Worker if (checkUriPermission(expected.requireUrisNotGranted[ui], 164*b7c941bbSAndroid Build Coastguard Worker Process.myPid(), Process.myUid(), 165*b7c941bbSAndroid Build Coastguard Worker Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 166*b7c941bbSAndroid Build Coastguard Worker != PackageManager.PERMISSION_DENIED) { 167*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, 168*b7c941bbSAndroid Build Coastguard Worker permCheckRead, permCheckWrite, null, 169*b7c941bbSAndroid Build Coastguard Worker "Not expected write permission but granted: " 170*b7c941bbSAndroid Build Coastguard Worker + expected.requireUrisNotGranted[ui] 171*b7c941bbSAndroid Build Coastguard Worker + " @ #" + index); 172*b7c941bbSAndroid Build Coastguard Worker return false; 173*b7c941bbSAndroid Build Coastguard Worker } 174*b7c941bbSAndroid Build Coastguard Worker } 175*b7c941bbSAndroid Build Coastguard Worker } 176*b7c941bbSAndroid Build Coastguard Worker } 177*b7c941bbSAndroid Build Coastguard Worker 178*b7c941bbSAndroid Build Coastguard Worker flags = expected.flags; 179*b7c941bbSAndroid Build Coastguard Worker 180*b7c941bbSAndroid Build Coastguard Worker if ((flags & TestWorkItem.FLAG_WAIT_FOR_STOP) != 0) { 181*b7c941bbSAndroid Build Coastguard Worker Log.i(TAG, "Now waiting to stop"); 182*b7c941bbSAndroid Build Coastguard Worker mWaitingForStop = true; 183*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyWaitingForStop(); 184*b7c941bbSAndroid Build Coastguard Worker return true; 185*b7c941bbSAndroid Build Coastguard Worker } 186*b7c941bbSAndroid Build Coastguard Worker 187*b7c941bbSAndroid Build Coastguard Worker if ((flags & TestWorkItem.FLAG_COMPLETE_NEXT) != 0) { 188*b7c941bbSAndroid Build Coastguard Worker if (!processNextPendingCompletion()) { 189*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, 190*b7c941bbSAndroid Build Coastguard Worker 0, 0, null, 191*b7c941bbSAndroid Build Coastguard Worker "Expected to complete next pending work but there was none: " 192*b7c941bbSAndroid Build Coastguard Worker + " @ #" + index); 193*b7c941bbSAndroid Build Coastguard Worker return false; 194*b7c941bbSAndroid Build Coastguard Worker } 195*b7c941bbSAndroid Build Coastguard Worker } 196*b7c941bbSAndroid Build Coastguard Worker } 197*b7c941bbSAndroid Build Coastguard Worker 198*b7c941bbSAndroid Build Coastguard Worker if ((flags & TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_BACK) != 0) { 199*b7c941bbSAndroid Build Coastguard Worker mPendingCompletions.add(work); 200*b7c941bbSAndroid Build Coastguard Worker } else if ((flags & TestWorkItem.FLAG_DELAY_COMPLETE_PUSH_TOP) != 0) { 201*b7c941bbSAndroid Build Coastguard Worker mPendingCompletions.add(0, work); 202*b7c941bbSAndroid Build Coastguard Worker } else { 203*b7c941bbSAndroid Build Coastguard Worker mParams.completeWork(work); 204*b7c941bbSAndroid Build Coastguard Worker } 205*b7c941bbSAndroid Build Coastguard Worker 206*b7c941bbSAndroid Build Coastguard Worker if (index < expectedWork.length) { 207*b7c941bbSAndroid Build Coastguard Worker TestWorkItem expected = expectedWork[index]; 208*b7c941bbSAndroid Build Coastguard Worker if (expected.subitems != null) { 209*b7c941bbSAndroid Build Coastguard Worker final TestWorkItem[] sub = expected.subitems; 210*b7c941bbSAndroid Build Coastguard Worker final JobInfo ji = expected.jobInfo; 211*b7c941bbSAndroid Build Coastguard Worker final JobScheduler js = (JobScheduler) getSystemService( 212*b7c941bbSAndroid Build Coastguard Worker Context.JOB_SCHEDULER_SERVICE); 213*b7c941bbSAndroid Build Coastguard Worker for (int subi = 0; subi < sub.length; subi++) { 214*b7c941bbSAndroid Build Coastguard Worker js.enqueue(ji, new JobWorkItem(sub[subi].intent)); 215*b7c941bbSAndroid Build Coastguard Worker } 216*b7c941bbSAndroid Build Coastguard Worker } 217*b7c941bbSAndroid Build Coastguard Worker } 218*b7c941bbSAndroid Build Coastguard Worker 219*b7c941bbSAndroid Build Coastguard Worker index++; 220*b7c941bbSAndroid Build Coastguard Worker } 221*b7c941bbSAndroid Build Coastguard Worker 222*b7c941bbSAndroid Build Coastguard Worker if (processNextPendingCompletion()) { 223*b7c941bbSAndroid Build Coastguard Worker // We had some pending completions, clean them all out... 224*b7c941bbSAndroid Build Coastguard Worker while (processNextPendingCompletion()) { 225*b7c941bbSAndroid Build Coastguard Worker } 226*b7c941bbSAndroid Build Coastguard Worker // ...and we need to do a final dequeue to complete the job, which should not 227*b7c941bbSAndroid Build Coastguard Worker // return any remaining work. 228*b7c941bbSAndroid Build Coastguard Worker if ((work = params.dequeueWork()) != null) { 229*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, 230*b7c941bbSAndroid Build Coastguard Worker 0, 0, null, 231*b7c941bbSAndroid Build Coastguard Worker "Expected no remaining work after dequeue pending, but got: " + work); 232*b7c941bbSAndroid Build Coastguard Worker } 233*b7c941bbSAndroid Build Coastguard Worker } 234*b7c941bbSAndroid Build Coastguard Worker 235*b7c941bbSAndroid Build Coastguard Worker Log.i(TAG, "Done with all work at #" + index); 236*b7c941bbSAndroid Build Coastguard Worker // We don't notifyExecution here because we want to make sure the job properly 237*b7c941bbSAndroid Build Coastguard Worker // stops itself. 238*b7c941bbSAndroid Build Coastguard Worker return true; 239*b7c941bbSAndroid Build Coastguard Worker } else { 240*b7c941bbSAndroid Build Coastguard Worker boolean continueAfterStart 241*b7c941bbSAndroid Build Coastguard Worker = TestEnvironment.getTestEnvironment().handleContinueAfterStart(); 242*b7c941bbSAndroid Build Coastguard Worker try { 243*b7c941bbSAndroid Build Coastguard Worker if (!TestEnvironment.getTestEnvironment().awaitDoJob()) { 244*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead, 245*b7c941bbSAndroid Build Coastguard Worker permCheckWrite, null, "Spent too long waiting to start job"); 246*b7c941bbSAndroid Build Coastguard Worker return false; 247*b7c941bbSAndroid Build Coastguard Worker } 248*b7c941bbSAndroid Build Coastguard Worker } catch (InterruptedException e) { 249*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead, 250*b7c941bbSAndroid Build Coastguard Worker permCheckWrite, null, "Failed waiting to start job: " + e); 251*b7c941bbSAndroid Build Coastguard Worker return false; 252*b7c941bbSAndroid Build Coastguard Worker } 253*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead, 254*b7c941bbSAndroid Build Coastguard Worker permCheckWrite, null, null); 255*b7c941bbSAndroid Build Coastguard Worker return continueAfterStart; 256*b7c941bbSAndroid Build Coastguard Worker } 257*b7c941bbSAndroid Build Coastguard Worker } 258*b7c941bbSAndroid Build Coastguard Worker processNextPendingCompletion()259*b7c941bbSAndroid Build Coastguard Worker boolean processNextPendingCompletion() { 260*b7c941bbSAndroid Build Coastguard Worker if (mPendingCompletions.size() <= 0) { 261*b7c941bbSAndroid Build Coastguard Worker return false; 262*b7c941bbSAndroid Build Coastguard Worker } 263*b7c941bbSAndroid Build Coastguard Worker 264*b7c941bbSAndroid Build Coastguard Worker JobWorkItem next = mPendingCompletions.remove(0); 265*b7c941bbSAndroid Build Coastguard Worker mParams.completeWork(next); 266*b7c941bbSAndroid Build Coastguard Worker return true; 267*b7c941bbSAndroid Build Coastguard Worker } 268*b7c941bbSAndroid Build Coastguard Worker 269*b7c941bbSAndroid Build Coastguard Worker @Override onStopJob(JobParameters params)270*b7c941bbSAndroid Build Coastguard Worker public boolean onStopJob(JobParameters params) { 271*b7c941bbSAndroid Build Coastguard Worker Log.i(TAG, "Received stop callback"); 272*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyStopped(); 273*b7c941bbSAndroid Build Coastguard Worker return mWaitingForStop; 274*b7c941bbSAndroid Build Coastguard Worker } 275*b7c941bbSAndroid Build Coastguard Worker 276*b7c941bbSAndroid Build Coastguard Worker public static final class TestWorkItem { 277*b7c941bbSAndroid Build Coastguard Worker /** 278*b7c941bbSAndroid Build Coastguard Worker * Stop processing work for now, waiting for the service to be stopped. 279*b7c941bbSAndroid Build Coastguard Worker */ 280*b7c941bbSAndroid Build Coastguard Worker public static final int FLAG_WAIT_FOR_STOP = 1<<0; 281*b7c941bbSAndroid Build Coastguard Worker /** 282*b7c941bbSAndroid Build Coastguard Worker * Don't complete this work now, instead push it on the back of the stack of 283*b7c941bbSAndroid Build Coastguard Worker * pending completions. 284*b7c941bbSAndroid Build Coastguard Worker */ 285*b7c941bbSAndroid Build Coastguard Worker public static final int FLAG_DELAY_COMPLETE_PUSH_BACK = 1<<1; 286*b7c941bbSAndroid Build Coastguard Worker /** 287*b7c941bbSAndroid Build Coastguard Worker * Don't complete this work now, instead insert to the top of the stack of 288*b7c941bbSAndroid Build Coastguard Worker * pending completions. 289*b7c941bbSAndroid Build Coastguard Worker */ 290*b7c941bbSAndroid Build Coastguard Worker public static final int FLAG_DELAY_COMPLETE_PUSH_TOP = 1<<2; 291*b7c941bbSAndroid Build Coastguard Worker /** 292*b7c941bbSAndroid Build Coastguard Worker * Complete next pending completion on the stack before completing this one. 293*b7c941bbSAndroid Build Coastguard Worker */ 294*b7c941bbSAndroid Build Coastguard Worker public static final int FLAG_COMPLETE_NEXT = 1<<3; 295*b7c941bbSAndroid Build Coastguard Worker 296*b7c941bbSAndroid Build Coastguard Worker public final Intent intent; 297*b7c941bbSAndroid Build Coastguard Worker public final JobInfo jobInfo; 298*b7c941bbSAndroid Build Coastguard Worker public final int flags; 299*b7c941bbSAndroid Build Coastguard Worker public final int deliveryCount; 300*b7c941bbSAndroid Build Coastguard Worker public final TestWorkItem[] subitems; 301*b7c941bbSAndroid Build Coastguard Worker public final Uri[] requireUrisGranted; 302*b7c941bbSAndroid Build Coastguard Worker public final Uri[] requireUrisNotGranted; 303*b7c941bbSAndroid Build Coastguard Worker TestWorkItem(Intent _intent)304*b7c941bbSAndroid Build Coastguard Worker public TestWorkItem(Intent _intent) { 305*b7c941bbSAndroid Build Coastguard Worker intent = _intent; 306*b7c941bbSAndroid Build Coastguard Worker jobInfo = null; 307*b7c941bbSAndroid Build Coastguard Worker flags = 0; 308*b7c941bbSAndroid Build Coastguard Worker deliveryCount = 1; 309*b7c941bbSAndroid Build Coastguard Worker subitems = null; 310*b7c941bbSAndroid Build Coastguard Worker requireUrisGranted = null; 311*b7c941bbSAndroid Build Coastguard Worker requireUrisNotGranted = null; 312*b7c941bbSAndroid Build Coastguard Worker } 313*b7c941bbSAndroid Build Coastguard Worker TestWorkItem(Intent _intent, int _flags)314*b7c941bbSAndroid Build Coastguard Worker public TestWorkItem(Intent _intent, int _flags) { 315*b7c941bbSAndroid Build Coastguard Worker intent = _intent; 316*b7c941bbSAndroid Build Coastguard Worker jobInfo = null; 317*b7c941bbSAndroid Build Coastguard Worker flags = _flags; 318*b7c941bbSAndroid Build Coastguard Worker deliveryCount = 1; 319*b7c941bbSAndroid Build Coastguard Worker subitems = null; 320*b7c941bbSAndroid Build Coastguard Worker requireUrisGranted = null; 321*b7c941bbSAndroid Build Coastguard Worker requireUrisNotGranted = null; 322*b7c941bbSAndroid Build Coastguard Worker } 323*b7c941bbSAndroid Build Coastguard Worker TestWorkItem(Intent _intent, int _flags, int _deliveryCount)324*b7c941bbSAndroid Build Coastguard Worker public TestWorkItem(Intent _intent, int _flags, int _deliveryCount) { 325*b7c941bbSAndroid Build Coastguard Worker intent = _intent; 326*b7c941bbSAndroid Build Coastguard Worker jobInfo = null; 327*b7c941bbSAndroid Build Coastguard Worker flags = _flags; 328*b7c941bbSAndroid Build Coastguard Worker deliveryCount = _deliveryCount; 329*b7c941bbSAndroid Build Coastguard Worker subitems = null; 330*b7c941bbSAndroid Build Coastguard Worker requireUrisGranted = null; 331*b7c941bbSAndroid Build Coastguard Worker requireUrisNotGranted = null; 332*b7c941bbSAndroid Build Coastguard Worker } 333*b7c941bbSAndroid Build Coastguard Worker TestWorkItem(Intent _intent, JobInfo _jobInfo, TestWorkItem[] _subitems)334*b7c941bbSAndroid Build Coastguard Worker public TestWorkItem(Intent _intent, JobInfo _jobInfo, TestWorkItem[] _subitems) { 335*b7c941bbSAndroid Build Coastguard Worker intent = _intent; 336*b7c941bbSAndroid Build Coastguard Worker jobInfo = _jobInfo; 337*b7c941bbSAndroid Build Coastguard Worker flags = 0; 338*b7c941bbSAndroid Build Coastguard Worker deliveryCount = 1; 339*b7c941bbSAndroid Build Coastguard Worker subitems = _subitems; 340*b7c941bbSAndroid Build Coastguard Worker requireUrisGranted = null; 341*b7c941bbSAndroid Build Coastguard Worker requireUrisNotGranted = null; 342*b7c941bbSAndroid Build Coastguard Worker } 343*b7c941bbSAndroid Build Coastguard Worker TestWorkItem(Intent _intent, Uri[] _requireUrisGranted, Uri[] _requireUrisNotGranted)344*b7c941bbSAndroid Build Coastguard Worker public TestWorkItem(Intent _intent, Uri[] _requireUrisGranted, 345*b7c941bbSAndroid Build Coastguard Worker Uri[] _requireUrisNotGranted) { 346*b7c941bbSAndroid Build Coastguard Worker intent = _intent; 347*b7c941bbSAndroid Build Coastguard Worker jobInfo = null; 348*b7c941bbSAndroid Build Coastguard Worker flags = 0; 349*b7c941bbSAndroid Build Coastguard Worker deliveryCount = 1; 350*b7c941bbSAndroid Build Coastguard Worker subitems = null; 351*b7c941bbSAndroid Build Coastguard Worker requireUrisGranted = _requireUrisGranted; 352*b7c941bbSAndroid Build Coastguard Worker requireUrisNotGranted = _requireUrisNotGranted; 353*b7c941bbSAndroid Build Coastguard Worker } 354*b7c941bbSAndroid Build Coastguard Worker 355*b7c941bbSAndroid Build Coastguard Worker @Override toString()356*b7c941bbSAndroid Build Coastguard Worker public String toString() { 357*b7c941bbSAndroid Build Coastguard Worker return "TestWorkItem { " + intent + " dc=" + deliveryCount + " }"; 358*b7c941bbSAndroid Build Coastguard Worker } 359*b7c941bbSAndroid Build Coastguard Worker } 360*b7c941bbSAndroid Build Coastguard Worker 361*b7c941bbSAndroid Build Coastguard Worker /** 362*b7c941bbSAndroid Build Coastguard Worker * Configures the expected behaviour for each test. This object is shared across consecutive 363*b7c941bbSAndroid Build Coastguard Worker * tests, so to clear state each test is responsible for calling 364*b7c941bbSAndroid Build Coastguard Worker * {@link TestEnvironment#setUp()}. 365*b7c941bbSAndroid Build Coastguard Worker */ 366*b7c941bbSAndroid Build Coastguard Worker public static final class TestEnvironment { 367*b7c941bbSAndroid Build Coastguard Worker 368*b7c941bbSAndroid Build Coastguard Worker private static TestEnvironment kTestEnvironment; 369*b7c941bbSAndroid Build Coastguard Worker //public static final int INVALID_JOB_ID = -1; 370*b7c941bbSAndroid Build Coastguard Worker 371*b7c941bbSAndroid Build Coastguard Worker private CountDownLatch mLatch; 372*b7c941bbSAndroid Build Coastguard Worker private CountDownLatch mWaitingForStopLatch; 373*b7c941bbSAndroid Build Coastguard Worker private CountDownLatch mDoJobLatch; 374*b7c941bbSAndroid Build Coastguard Worker private CountDownLatch mStoppedLatch; 375*b7c941bbSAndroid Build Coastguard Worker private CountDownLatch mDoWorkLatch; 376*b7c941bbSAndroid Build Coastguard Worker private TestWorkItem[] mExpectedWork; 377*b7c941bbSAndroid Build Coastguard Worker private boolean mContinueAfterStart; 378*b7c941bbSAndroid Build Coastguard Worker private JobParameters mExecutedJobParameters; 379*b7c941bbSAndroid Build Coastguard Worker private int mExecutedPermCheckRead; 380*b7c941bbSAndroid Build Coastguard Worker private int mExecutedPermCheckWrite; 381*b7c941bbSAndroid Build Coastguard Worker private ArrayList<JobWorkItem> mExecutedReceivedWork; 382*b7c941bbSAndroid Build Coastguard Worker private String mExecutedErrorMessage; 383*b7c941bbSAndroid Build Coastguard Worker getTestEnvironment()384*b7c941bbSAndroid Build Coastguard Worker public static TestEnvironment getTestEnvironment() { 385*b7c941bbSAndroid Build Coastguard Worker if (kTestEnvironment == null) { 386*b7c941bbSAndroid Build Coastguard Worker kTestEnvironment = new TestEnvironment(); 387*b7c941bbSAndroid Build Coastguard Worker } 388*b7c941bbSAndroid Build Coastguard Worker return kTestEnvironment; 389*b7c941bbSAndroid Build Coastguard Worker } 390*b7c941bbSAndroid Build Coastguard Worker getExpectedWork()391*b7c941bbSAndroid Build Coastguard Worker public TestWorkItem[] getExpectedWork() { 392*b7c941bbSAndroid Build Coastguard Worker return mExpectedWork; 393*b7c941bbSAndroid Build Coastguard Worker } 394*b7c941bbSAndroid Build Coastguard Worker getLastJobParameters()395*b7c941bbSAndroid Build Coastguard Worker public JobParameters getLastJobParameters() { 396*b7c941bbSAndroid Build Coastguard Worker return mExecutedJobParameters; 397*b7c941bbSAndroid Build Coastguard Worker } 398*b7c941bbSAndroid Build Coastguard Worker getLastPermCheckRead()399*b7c941bbSAndroid Build Coastguard Worker public int getLastPermCheckRead() { 400*b7c941bbSAndroid Build Coastguard Worker return mExecutedPermCheckRead; 401*b7c941bbSAndroid Build Coastguard Worker } 402*b7c941bbSAndroid Build Coastguard Worker getLastPermCheckWrite()403*b7c941bbSAndroid Build Coastguard Worker public int getLastPermCheckWrite() { 404*b7c941bbSAndroid Build Coastguard Worker return mExecutedPermCheckWrite; 405*b7c941bbSAndroid Build Coastguard Worker } 406*b7c941bbSAndroid Build Coastguard Worker getLastReceivedWork()407*b7c941bbSAndroid Build Coastguard Worker public ArrayList<JobWorkItem> getLastReceivedWork() { 408*b7c941bbSAndroid Build Coastguard Worker return mExecutedReceivedWork; 409*b7c941bbSAndroid Build Coastguard Worker } 410*b7c941bbSAndroid Build Coastguard Worker getLastErrorMessage()411*b7c941bbSAndroid Build Coastguard Worker public String getLastErrorMessage() { 412*b7c941bbSAndroid Build Coastguard Worker return mExecutedErrorMessage; 413*b7c941bbSAndroid Build Coastguard Worker } 414*b7c941bbSAndroid Build Coastguard Worker 415*b7c941bbSAndroid Build Coastguard Worker /** 416*b7c941bbSAndroid Build Coastguard Worker * Block the test thread, waiting on the JobScheduler to execute some previously scheduled 417*b7c941bbSAndroid Build Coastguard Worker * job on this service. 418*b7c941bbSAndroid Build Coastguard Worker */ awaitExecution()419*b7c941bbSAndroid Build Coastguard Worker public boolean awaitExecution() throws InterruptedException { 420*b7c941bbSAndroid Build Coastguard Worker return awaitExecution(DEFAULT_TIMEOUT_MILLIS); 421*b7c941bbSAndroid Build Coastguard Worker } 422*b7c941bbSAndroid Build Coastguard Worker awaitExecution(long timeoutMillis)423*b7c941bbSAndroid Build Coastguard Worker public boolean awaitExecution(long timeoutMillis) throws InterruptedException { 424*b7c941bbSAndroid Build Coastguard Worker final boolean executed = mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS); 425*b7c941bbSAndroid Build Coastguard Worker if (getLastErrorMessage() != null) { 426*b7c941bbSAndroid Build Coastguard Worker Assert.fail(getLastErrorMessage()); 427*b7c941bbSAndroid Build Coastguard Worker } 428*b7c941bbSAndroid Build Coastguard Worker return executed; 429*b7c941bbSAndroid Build Coastguard Worker } 430*b7c941bbSAndroid Build Coastguard Worker 431*b7c941bbSAndroid Build Coastguard Worker /** 432*b7c941bbSAndroid Build Coastguard Worker * Block the test thread, expecting to timeout but still listening to ensure that no jobs 433*b7c941bbSAndroid Build Coastguard Worker * land in the interim. 434*b7c941bbSAndroid Build Coastguard Worker * @return True if the latch timed out waiting on an execution. 435*b7c941bbSAndroid Build Coastguard Worker */ awaitTimeout()436*b7c941bbSAndroid Build Coastguard Worker public boolean awaitTimeout() throws InterruptedException { 437*b7c941bbSAndroid Build Coastguard Worker return awaitTimeout(DEFAULT_TIMEOUT_MILLIS); 438*b7c941bbSAndroid Build Coastguard Worker } 439*b7c941bbSAndroid Build Coastguard Worker awaitTimeout(long timeoutMillis)440*b7c941bbSAndroid Build Coastguard Worker public boolean awaitTimeout(long timeoutMillis) throws InterruptedException { 441*b7c941bbSAndroid Build Coastguard Worker return !mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS); 442*b7c941bbSAndroid Build Coastguard Worker } 443*b7c941bbSAndroid Build Coastguard Worker awaitWaitingForStop()444*b7c941bbSAndroid Build Coastguard Worker public boolean awaitWaitingForStop() throws InterruptedException { 445*b7c941bbSAndroid Build Coastguard Worker return mWaitingForStopLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 446*b7c941bbSAndroid Build Coastguard Worker } 447*b7c941bbSAndroid Build Coastguard Worker awaitDoWork()448*b7c941bbSAndroid Build Coastguard Worker public boolean awaitDoWork() throws InterruptedException { 449*b7c941bbSAndroid Build Coastguard Worker return mDoWorkLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 450*b7c941bbSAndroid Build Coastguard Worker } 451*b7c941bbSAndroid Build Coastguard Worker awaitDoJob()452*b7c941bbSAndroid Build Coastguard Worker public boolean awaitDoJob() throws InterruptedException { 453*b7c941bbSAndroid Build Coastguard Worker if (mDoJobLatch == null) { 454*b7c941bbSAndroid Build Coastguard Worker return true; 455*b7c941bbSAndroid Build Coastguard Worker } 456*b7c941bbSAndroid Build Coastguard Worker return mDoJobLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 457*b7c941bbSAndroid Build Coastguard Worker } 458*b7c941bbSAndroid Build Coastguard Worker awaitStopped()459*b7c941bbSAndroid Build Coastguard Worker public boolean awaitStopped() throws InterruptedException { 460*b7c941bbSAndroid Build Coastguard Worker return mStoppedLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 461*b7c941bbSAndroid Build Coastguard Worker } 462*b7c941bbSAndroid Build Coastguard Worker notifyExecution(JobParameters params, int permCheckRead, int permCheckWrite, ArrayList<JobWorkItem> receivedWork, String errorMsg)463*b7c941bbSAndroid Build Coastguard Worker private void notifyExecution(JobParameters params, int permCheckRead, int permCheckWrite, 464*b7c941bbSAndroid Build Coastguard Worker ArrayList<JobWorkItem> receivedWork, String errorMsg) { 465*b7c941bbSAndroid Build Coastguard Worker //Log.d(TAG, "Job executed:" + params.getJobId()); 466*b7c941bbSAndroid Build Coastguard Worker mExecutedJobParameters = params; 467*b7c941bbSAndroid Build Coastguard Worker mExecutedPermCheckRead = permCheckRead; 468*b7c941bbSAndroid Build Coastguard Worker mExecutedPermCheckWrite = permCheckWrite; 469*b7c941bbSAndroid Build Coastguard Worker mExecutedReceivedWork = receivedWork; 470*b7c941bbSAndroid Build Coastguard Worker mExecutedErrorMessage = errorMsg; 471*b7c941bbSAndroid Build Coastguard Worker mLatch.countDown(); 472*b7c941bbSAndroid Build Coastguard Worker } 473*b7c941bbSAndroid Build Coastguard Worker notifyWaitingForStop()474*b7c941bbSAndroid Build Coastguard Worker private void notifyWaitingForStop() { 475*b7c941bbSAndroid Build Coastguard Worker mWaitingForStopLatch.countDown(); 476*b7c941bbSAndroid Build Coastguard Worker } 477*b7c941bbSAndroid Build Coastguard Worker notifyStopped()478*b7c941bbSAndroid Build Coastguard Worker private void notifyStopped() { 479*b7c941bbSAndroid Build Coastguard Worker if (mStoppedLatch != null) { 480*b7c941bbSAndroid Build Coastguard Worker mStoppedLatch.countDown(); 481*b7c941bbSAndroid Build Coastguard Worker } 482*b7c941bbSAndroid Build Coastguard Worker } 483*b7c941bbSAndroid Build Coastguard Worker setExpectedExecutions(int numExecutions)484*b7c941bbSAndroid Build Coastguard Worker public void setExpectedExecutions(int numExecutions) { 485*b7c941bbSAndroid Build Coastguard Worker // For no executions expected, set count to 1 so we can still block for the timeout. 486*b7c941bbSAndroid Build Coastguard Worker if (numExecutions == 0) { 487*b7c941bbSAndroid Build Coastguard Worker mLatch = new CountDownLatch(1); 488*b7c941bbSAndroid Build Coastguard Worker } else { 489*b7c941bbSAndroid Build Coastguard Worker mLatch = new CountDownLatch(numExecutions); 490*b7c941bbSAndroid Build Coastguard Worker } 491*b7c941bbSAndroid Build Coastguard Worker mWaitingForStopLatch = null; 492*b7c941bbSAndroid Build Coastguard Worker mDoJobLatch = null; 493*b7c941bbSAndroid Build Coastguard Worker mStoppedLatch = null; 494*b7c941bbSAndroid Build Coastguard Worker mDoWorkLatch = null; 495*b7c941bbSAndroid Build Coastguard Worker mExpectedWork = null; 496*b7c941bbSAndroid Build Coastguard Worker mContinueAfterStart = false; 497*b7c941bbSAndroid Build Coastguard Worker } 498*b7c941bbSAndroid Build Coastguard Worker setExpectedWaitForStop()499*b7c941bbSAndroid Build Coastguard Worker public void setExpectedWaitForStop() { 500*b7c941bbSAndroid Build Coastguard Worker mWaitingForStopLatch = new CountDownLatch(1); 501*b7c941bbSAndroid Build Coastguard Worker } 502*b7c941bbSAndroid Build Coastguard Worker setExpectedWork(TestWorkItem[] work)503*b7c941bbSAndroid Build Coastguard Worker public void setExpectedWork(TestWorkItem[] work) { 504*b7c941bbSAndroid Build Coastguard Worker mExpectedWork = work; 505*b7c941bbSAndroid Build Coastguard Worker mDoWorkLatch = new CountDownLatch(1); 506*b7c941bbSAndroid Build Coastguard Worker } 507*b7c941bbSAndroid Build Coastguard Worker setExpectedStopped()508*b7c941bbSAndroid Build Coastguard Worker public void setExpectedStopped() { 509*b7c941bbSAndroid Build Coastguard Worker mStoppedLatch = new CountDownLatch(1); 510*b7c941bbSAndroid Build Coastguard Worker } 511*b7c941bbSAndroid Build Coastguard Worker readyToWork()512*b7c941bbSAndroid Build Coastguard Worker public void readyToWork() { 513*b7c941bbSAndroid Build Coastguard Worker mDoWorkLatch.countDown(); 514*b7c941bbSAndroid Build Coastguard Worker } 515*b7c941bbSAndroid Build Coastguard Worker setExpectedWaitForRun()516*b7c941bbSAndroid Build Coastguard Worker public void setExpectedWaitForRun() { 517*b7c941bbSAndroid Build Coastguard Worker mDoJobLatch = new CountDownLatch(1); 518*b7c941bbSAndroid Build Coastguard Worker } 519*b7c941bbSAndroid Build Coastguard Worker readyToRun()520*b7c941bbSAndroid Build Coastguard Worker public void readyToRun() { 521*b7c941bbSAndroid Build Coastguard Worker mDoJobLatch.countDown(); 522*b7c941bbSAndroid Build Coastguard Worker } 523*b7c941bbSAndroid Build Coastguard Worker setContinueAfterStart()524*b7c941bbSAndroid Build Coastguard Worker public void setContinueAfterStart() { 525*b7c941bbSAndroid Build Coastguard Worker mContinueAfterStart = true; 526*b7c941bbSAndroid Build Coastguard Worker } 527*b7c941bbSAndroid Build Coastguard Worker handleContinueAfterStart()528*b7c941bbSAndroid Build Coastguard Worker public boolean handleContinueAfterStart() { 529*b7c941bbSAndroid Build Coastguard Worker boolean res = mContinueAfterStart; 530*b7c941bbSAndroid Build Coastguard Worker mContinueAfterStart = false; 531*b7c941bbSAndroid Build Coastguard Worker return res; 532*b7c941bbSAndroid Build Coastguard Worker } 533*b7c941bbSAndroid Build Coastguard Worker 534*b7c941bbSAndroid Build Coastguard Worker /** Called in each testCase#setup */ setUp()535*b7c941bbSAndroid Build Coastguard Worker public void setUp() { 536*b7c941bbSAndroid Build Coastguard Worker mLatch = null; 537*b7c941bbSAndroid Build Coastguard Worker mExecutedJobParameters = null; 538*b7c941bbSAndroid Build Coastguard Worker } 539*b7c941bbSAndroid Build Coastguard Worker 540*b7c941bbSAndroid Build Coastguard Worker } 541*b7c941bbSAndroid Build Coastguard Worker }