1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.jobscheduler.cts; 17 18 import android.annotation.CallSuper; 19 import android.annotation.TargetApi; 20 import android.app.Instrumentation; 21 import android.app.job.JobScheduler; 22 import android.content.ClipData; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.PackageManager; 27 import android.jobscheduler.MockJobService; 28 import android.jobscheduler.TriggerContentJobService; 29 import android.net.Uri; 30 import android.os.Bundle; 31 import android.os.Process; 32 import android.os.SystemClock; 33 import android.os.UserHandle; 34 import android.provider.DeviceConfig; 35 import android.test.InstrumentationTestCase; 36 import android.util.Log; 37 38 import com.android.compatibility.common.util.BatteryUtils; 39 import com.android.compatibility.common.util.DeviceConfigStateHelper; 40 import com.android.compatibility.common.util.SystemUtil; 41 42 import java.io.IOException; 43 44 /** 45 * Common functionality from which the other test case classes derive. 46 */ 47 @TargetApi(21) 48 public abstract class BaseJobSchedulerTest extends InstrumentationTestCase { 49 /** Environment that notifies of JobScheduler callbacks. */ 50 static MockJobService.TestEnvironment kTestEnvironment = 51 MockJobService.TestEnvironment.getTestEnvironment(); 52 static TriggerContentJobService.TestEnvironment kTriggerTestEnvironment = 53 TriggerContentJobService.TestEnvironment.getTestEnvironment(); 54 /** Handle for the service which receives the execution callbacks from the JobScheduler. */ 55 static ComponentName kJobServiceComponent; 56 static ComponentName kTriggerContentServiceComponent; 57 JobScheduler mJobScheduler; 58 59 Context mContext; 60 DeviceConfigStateHelper mDeviceConfigStateHelper; 61 62 static final String MY_PACKAGE = "android.jobscheduler.cts"; 63 64 static final String JOBPERM_PACKAGE = "android.jobscheduler.cts.jobperm"; 65 static final String JOBPERM_AUTHORITY = "android.jobscheduler.cts.jobperm.provider"; 66 static final String JOBPERM_PERM = "android.jobscheduler.cts.jobperm.perm"; 67 68 Uri mFirstUri; 69 Bundle mFirstUriBundle; 70 Uri mSecondUri; 71 Bundle mSecondUriBundle; 72 ClipData mFirstClipData; 73 ClipData mSecondClipData; 74 75 boolean mStorageStateChanged; 76 77 @Override injectInstrumentation(Instrumentation instrumentation)78 public void injectInstrumentation(Instrumentation instrumentation) { 79 super.injectInstrumentation(instrumentation); 80 mContext = instrumentation.getContext(); 81 kJobServiceComponent = new ComponentName(getContext(), MockJobService.class); 82 kTriggerContentServiceComponent = new ComponentName(getContext(), 83 TriggerContentJobService.class); 84 mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE); 85 mFirstUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/foo"); 86 mFirstUriBundle = new Bundle(); 87 mFirstUriBundle.putParcelable("uri", mFirstUri); 88 mSecondUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/bar"); 89 mSecondUriBundle = new Bundle(); 90 mSecondUriBundle.putParcelable("uri", mSecondUri); 91 mFirstClipData = new ClipData("JobPerm1", new String[] { "application/*" }, 92 new ClipData.Item(mFirstUri)); 93 mSecondClipData = new ClipData("JobPerm2", new String[] { "application/*" }, 94 new ClipData.Item(mSecondUri)); 95 try { 96 SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive " 97 + mContext.getPackageName() + " false"); 98 } catch (IOException e) { 99 Log.w("ConstraintTest", "Failed setting inactive false", e); 100 } 101 } 102 getContext()103 public Context getContext() { 104 return mContext; 105 } 106 107 @CallSuper 108 @Override setUp()109 public void setUp() throws Exception { 110 super.setUp(); 111 mDeviceConfigStateHelper = 112 new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_JOB_SCHEDULER); 113 kTestEnvironment.setUp(); 114 kTriggerTestEnvironment.setUp(); 115 mJobScheduler.cancelAll(); 116 } 117 118 @CallSuper 119 @Override tearDown()120 public void tearDown() throws Exception { 121 SystemUtil.runShellCommand(getInstrumentation(), "cmd battery reset"); 122 if (mStorageStateChanged) { 123 // Put storage service back in to normal operation. 124 SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset"); 125 mStorageStateChanged = false; 126 } 127 SystemUtil.runShellCommand(getInstrumentation(), 128 "cmd jobscheduler reset-execution-quota -u current " 129 + kJobServiceComponent.getPackageName()); 130 mDeviceConfigStateHelper.restoreOriginalValues(); 131 132 // The super method should be called at the end. 133 super.tearDown(); 134 } 135 assertHasUriPermission(Uri uri, int grantFlags)136 public void assertHasUriPermission(Uri uri, int grantFlags) { 137 if ((grantFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { 138 assertEquals(PackageManager.PERMISSION_GRANTED, 139 getContext().checkUriPermission(uri, Process.myPid(), 140 Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION)); 141 } 142 if ((grantFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { 143 assertEquals(PackageManager.PERMISSION_GRANTED, 144 getContext().checkUriPermission(uri, Process.myPid(), 145 Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION)); 146 } 147 } 148 waitPermissionRevoke(Uri uri, int access, long timeout)149 void waitPermissionRevoke(Uri uri, int access, long timeout) { 150 long startTime = SystemClock.elapsedRealtime(); 151 while (getContext().checkUriPermission(uri, Process.myPid(), Process.myUid(), access) 152 != PackageManager.PERMISSION_DENIED) { 153 try { 154 Thread.sleep(50); 155 } catch (InterruptedException e) { 156 } 157 if ((SystemClock.elapsedRealtime()-startTime) >= timeout) { 158 fail("Timed out waiting for permission revoke"); 159 } 160 } 161 } 162 163 // Note we are just using storage state as a way to control when the job gets executed. setStorageStateLow(boolean low)164 void setStorageStateLow(boolean low) throws Exception { 165 mStorageStateChanged = true; 166 String res; 167 if (low) { 168 res = SystemUtil.runShellCommand(getInstrumentation(), 169 "cmd devicestoragemonitor force-low -f"); 170 } else { 171 res = SystemUtil.runShellCommand(getInstrumentation(), 172 "cmd devicestoragemonitor force-not-low -f"); 173 } 174 int seq = Integer.parseInt(res.trim()); 175 long startTime = SystemClock.elapsedRealtime(); 176 177 // Wait for the storage update to be processed by job scheduler before proceeding. 178 int curSeq; 179 do { 180 curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(), 181 "cmd jobscheduler get-storage-seq").trim()); 182 if (curSeq == seq) { 183 return; 184 } 185 } while ((SystemClock.elapsedRealtime()-startTime) < 1000); 186 187 fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq); 188 } 189 getJobState(int jobId)190 String getJobState(int jobId) throws Exception { 191 return SystemUtil.runShellCommand(getInstrumentation(), 192 "cmd jobscheduler get-job-state --user cur " 193 + kJobServiceComponent.getPackageName() + " " + jobId).trim(); 194 } 195 assertJobReady(int jobId)196 void assertJobReady(int jobId) throws Exception { 197 String state = getJobState(jobId); 198 assertTrue("Job unexpectedly not ready, in state: " + state, state.contains("ready")); 199 } 200 assertJobWaiting(int jobId)201 void assertJobWaiting(int jobId) throws Exception { 202 String state = getJobState(jobId); 203 assertTrue("Job unexpectedly not waiting, in state: " + state, state.contains("waiting")); 204 } 205 assertJobNotReady(int jobId)206 void assertJobNotReady(int jobId) throws Exception { 207 String state = getJobState(jobId); 208 assertTrue("Job unexpectedly ready, in state: " + state, !state.contains("ready")); 209 } 210 211 /** 212 * Set the screen state. 213 */ toggleScreenOn(final boolean screenon)214 static void toggleScreenOn(final boolean screenon) throws Exception { 215 BatteryUtils.turnOnScreen(screenon); 216 // Wait a little bit for the broadcasts to be processed. 217 Thread.sleep(2_000); 218 } 219 220 /** Asks (not forces) JobScheduler to run the job if constraints are met. */ runSatisfiedJob(int jobId)221 void runSatisfiedJob(int jobId) throws Exception { 222 SystemUtil.runShellCommand(getInstrumentation(), 223 "cmd jobscheduler run -s" 224 + " -u " + UserHandle.myUserId() 225 + " " + kJobServiceComponent.getPackageName() 226 + " " + jobId); 227 } 228 } 229