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.TargetApi; 19 import android.app.Instrumentation; 20 import android.app.job.JobScheduler; 21 import android.content.ClipData; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.jobscheduler.MockJobService; 27 import android.jobscheduler.TriggerContentJobService; 28 import android.net.Uri; 29 import android.os.Bundle; 30 import android.os.Process; 31 import android.os.SystemClock; 32 import android.test.InstrumentationTestCase; 33 import android.util.Log; 34 35 import com.android.compatibility.common.util.SystemUtil; 36 37 import java.io.IOException; 38 39 /** 40 * Common functionality from which the other test case classes derive. 41 */ 42 @TargetApi(21) 43 public abstract class ConstraintTest extends InstrumentationTestCase { 44 /** Force the scheduler to consider the device to be on stable charging. */ 45 private static final Intent EXPEDITE_STABLE_CHARGING = 46 new Intent("com.android.server.task.controllers.BatteryController.ACTION_CHARGING_STABLE"); 47 48 /** Environment that notifies of JobScheduler callbacks. */ 49 static MockJobService.TestEnvironment kTestEnvironment = 50 MockJobService.TestEnvironment.getTestEnvironment(); 51 static TriggerContentJobService.TestEnvironment kTriggerTestEnvironment = 52 TriggerContentJobService.TestEnvironment.getTestEnvironment(); 53 /** Handle for the service which receives the execution callbacks from the JobScheduler. */ 54 static ComponentName kJobServiceComponent; 55 static ComponentName kTriggerContentServiceComponent; 56 JobScheduler mJobScheduler; 57 58 Context mContext; 59 60 static final String MY_PACKAGE = "android.jobscheduler.cts"; 61 62 static final String JOBPERM_PACKAGE = "android.jobscheduler.cts.jobperm"; 63 static final String JOBPERM_AUTHORITY = "android.jobscheduler.cts.jobperm.provider"; 64 static final String JOBPERM_PERM = "android.jobscheduler.cts.jobperm.perm"; 65 66 Uri mFirstUri; 67 Bundle mFirstUriBundle; 68 Uri mSecondUri; 69 Bundle mSecondUriBundle; 70 ClipData mFirstClipData; 71 ClipData mSecondClipData; 72 73 boolean mStorageStateChanged; 74 75 @Override 76 public void injectInstrumentation(Instrumentation instrumentation) { 77 super.injectInstrumentation(instrumentation); 78 mContext = instrumentation.getContext(); 79 kJobServiceComponent = new ComponentName(getContext(), MockJobService.class); 80 kTriggerContentServiceComponent = new ComponentName(getContext(), 81 TriggerContentJobService.class); 82 mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE); 83 mFirstUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/foo"); 84 mFirstUriBundle = new Bundle(); 85 mFirstUriBundle.putParcelable("uri", mFirstUri); 86 mSecondUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/bar"); 87 mSecondUriBundle = new Bundle(); 88 mSecondUriBundle.putParcelable("uri", mSecondUri); 89 mFirstClipData = new ClipData("JobPerm1", new String[] { "application/*" }, 90 new ClipData.Item(mFirstUri)); 91 mSecondClipData = new ClipData("JobPerm2", new String[] { "application/*" }, 92 new ClipData.Item(mSecondUri)); 93 try { 94 SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive " 95 + mContext.getPackageName() + " false"); 96 } catch (IOException e) { 97 Log.w("ConstraintTest", "Failed setting inactive false", e); 98 } 99 } 100 101 public Context getContext() { 102 return mContext; 103 } 104 105 @Override 106 public void setUp() throws Exception { 107 super.setUp(); 108 kTestEnvironment.setUp(); 109 kTriggerTestEnvironment.setUp(); 110 mJobScheduler.cancelAll(); 111 } 112 113 @Override 114 public void tearDown() throws Exception { 115 if (mStorageStateChanged) { 116 // Put storage service back in to normal operation. 117 SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset"); 118 mStorageStateChanged = false; 119 } 120 } 121 122 /** 123 * The scheduler will usually only flush its queue of unexpired jobs when the device is 124 * considered to be on stable power - that is, plugged in for a period of 2 minutes. 125 * Rather than wait for this to happen, we cheat and send this broadcast instead. 126 */ 127 protected void sendExpediteStableChargingBroadcast() { 128 getContext().sendBroadcast(EXPEDITE_STABLE_CHARGING); 129 } 130 131 public void assertHasUriPermission(Uri uri, int grantFlags) { 132 if ((grantFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { 133 assertEquals(PackageManager.PERMISSION_GRANTED, 134 getContext().checkUriPermission(uri, Process.myPid(), 135 Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION)); 136 } 137 if ((grantFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { 138 assertEquals(PackageManager.PERMISSION_GRANTED, 139 getContext().checkUriPermission(uri, Process.myPid(), 140 Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION)); 141 } 142 } 143 144 void waitPermissionRevoke(Uri uri, int access, long timeout) { 145 long startTime = SystemClock.elapsedRealtime(); 146 while (getContext().checkUriPermission(uri, Process.myPid(), Process.myUid(), access) 147 != PackageManager.PERMISSION_DENIED) { 148 try { 149 Thread.sleep(50); 150 } catch (InterruptedException e) { 151 } 152 if ((SystemClock.elapsedRealtime()-startTime) >= timeout) { 153 fail("Timed out waiting for permission revoke"); 154 } 155 } 156 } 157 158 // Note we are just using storage state as a way to control when the job gets executed. 159 void setStorageState(boolean low) throws Exception { 160 mStorageStateChanged = true; 161 String res; 162 if (low) { 163 res = SystemUtil.runShellCommand(getInstrumentation(), 164 "cmd devicestoragemonitor force-low -f"); 165 } else { 166 res = SystemUtil.runShellCommand(getInstrumentation(), 167 "cmd devicestoragemonitor force-not-low -f"); 168 } 169 int seq = Integer.parseInt(res.trim()); 170 long startTime = SystemClock.elapsedRealtime(); 171 172 // Wait for the storage update to be processed by job scheduler before proceeding. 173 int curSeq; 174 do { 175 curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(), 176 "cmd jobscheduler get-storage-seq").trim()); 177 if (curSeq == seq) { 178 return; 179 } 180 } while ((SystemClock.elapsedRealtime()-startTime) < 1000); 181 182 fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq); 183 } 184 185 String getJobState(int jobId) throws Exception { 186 return SystemUtil.runShellCommand(getInstrumentation(), 187 "cmd jobscheduler get-job-state " + kJobServiceComponent.getPackageName() 188 + " " + jobId).trim(); 189 } 190 191 void assertJobReady(int jobId) throws Exception { 192 String state = getJobState(jobId); 193 assertTrue("Job unexpectedly not ready, in state: " + state, state.contains("ready")); 194 } 195 196 void assertJobWaiting(int jobId) throws Exception { 197 String state = getJobState(jobId); 198 assertTrue("Job unexpectedly not waiting, in state: " + state, state.contains("waiting")); 199 } 200 201 void assertJobNotReady(int jobId) throws Exception { 202 String state = getJobState(jobId); 203 assertTrue("Job unexpectedly ready, in state: " + state, !state.contains("ready")); 204 } 205 } 206