• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.compatibility.common.util.TestUtils.waitUntil;
19 
20 import android.annotation.CallSuper;
21 import android.annotation.TargetApi;
22 import android.app.Instrumentation;
23 import android.app.job.JobScheduler;
24 import android.content.ClipData;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.PackageManager;
29 import android.jobscheduler.MockJobService;
30 import android.jobscheduler.TriggerContentJobService;
31 import android.net.Uri;
32 import android.os.Bundle;
33 import android.os.Process;
34 import android.os.SystemClock;
35 import android.os.UserHandle;
36 import android.provider.DeviceConfig;
37 import android.provider.Settings;
38 import android.test.InstrumentationTestCase;
39 import android.util.Log;
40 
41 import com.android.compatibility.common.util.BatteryUtils;
42 import com.android.compatibility.common.util.DeviceConfigStateHelper;
43 import com.android.compatibility.common.util.SystemUtil;
44 
45 import java.io.IOException;
46 
47 /**
48  * Common functionality from which the other test case classes derive.
49  */
50 @TargetApi(21)
51 public abstract class BaseJobSchedulerTest extends InstrumentationTestCase {
52     /** Environment that notifies of JobScheduler callbacks. */
53     static MockJobService.TestEnvironment kTestEnvironment =
54             MockJobService.TestEnvironment.getTestEnvironment();
55     static TriggerContentJobService.TestEnvironment kTriggerTestEnvironment =
56             TriggerContentJobService.TestEnvironment.getTestEnvironment();
57     /** Handle for the service which receives the execution callbacks from the JobScheduler. */
58     static ComponentName kJobServiceComponent;
59     static ComponentName kTriggerContentServiceComponent;
60     JobScheduler mJobScheduler;
61 
62     Context mContext;
63     DeviceConfigStateHelper mDeviceConfigStateHelper;
64 
65     static final String MY_PACKAGE = "android.jobscheduler.cts";
66 
67     static final String JOBPERM_PACKAGE = "android.jobscheduler.cts.jobperm";
68     static final String JOBPERM_AUTHORITY = "android.jobscheduler.cts.jobperm.provider";
69     static final String JOBPERM_PERM = "android.jobscheduler.cts.jobperm.perm";
70 
71     Uri mFirstUri;
72     Bundle mFirstUriBundle;
73     Uri mSecondUri;
74     Bundle mSecondUriBundle;
75     ClipData mFirstClipData;
76     ClipData mSecondClipData;
77 
78     boolean mStorageStateChanged;
79 
80     private String mInitialBatteryStatsConstants;
81 
82     @Override
injectInstrumentation(Instrumentation instrumentation)83     public void injectInstrumentation(Instrumentation instrumentation) {
84         super.injectInstrumentation(instrumentation);
85         mContext = instrumentation.getContext();
86         kJobServiceComponent = new ComponentName(getContext(), MockJobService.class);
87         kTriggerContentServiceComponent = new ComponentName(getContext(),
88                 TriggerContentJobService.class);
89         mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
90         mFirstUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/foo");
91         mFirstUriBundle = new Bundle();
92         mFirstUriBundle.putParcelable("uri", mFirstUri);
93         mSecondUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/bar");
94         mSecondUriBundle = new Bundle();
95         mSecondUriBundle.putParcelable("uri", mSecondUri);
96         mFirstClipData = new ClipData("JobPerm1", new String[] { "application/*" },
97                 new ClipData.Item(mFirstUri));
98         mSecondClipData = new ClipData("JobPerm2", new String[] { "application/*" },
99                 new ClipData.Item(mSecondUri));
100         try {
101             SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
102                     + mContext.getPackageName() + " false");
103         } catch (IOException e) {
104             Log.w("ConstraintTest", "Failed setting inactive false", e);
105         }
106     }
107 
getContext()108     public Context getContext() {
109         return mContext;
110     }
111 
112     @CallSuper
113     @Override
setUp()114     public void setUp() throws Exception {
115         super.setUp();
116         mDeviceConfigStateHelper =
117                 new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_JOB_SCHEDULER);
118         kTestEnvironment.setUp();
119         kTriggerTestEnvironment.setUp();
120         mJobScheduler.cancelAll();
121 
122         mInitialBatteryStatsConstants = Settings.Global.getString(mContext.getContentResolver(),
123                 Settings.Global.BATTERY_STATS_CONSTANTS);
124         // Make sure ACTION_CHARGING is sent immediately.
125         Settings.Global.putString(mContext.getContentResolver(),
126                 Settings.Global.BATTERY_STATS_CONSTANTS, "battery_charged_delay_ms=0");
127     }
128 
129     @CallSuper
130     @Override
tearDown()131     public void tearDown() throws Exception {
132         SystemUtil.runShellCommand(getInstrumentation(), "cmd battery reset");
133         Settings.Global.putString(mContext.getContentResolver(),
134                 Settings.Global.BATTERY_STATS_CONSTANTS, mInitialBatteryStatsConstants);
135         if (mStorageStateChanged) {
136             // Put storage service back in to normal operation.
137             SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset");
138             mStorageStateChanged = false;
139         }
140         SystemUtil.runShellCommand(getInstrumentation(),
141                 "cmd jobscheduler reset-execution-quota -u current "
142                         + kJobServiceComponent.getPackageName());
143         mDeviceConfigStateHelper.restoreOriginalValues();
144 
145         // The super method should be called at the end.
146         super.tearDown();
147     }
148 
assertHasUriPermission(Uri uri, int grantFlags)149     public void assertHasUriPermission(Uri uri, int grantFlags) {
150         if ((grantFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
151             assertEquals(PackageManager.PERMISSION_GRANTED,
152                     getContext().checkUriPermission(uri, Process.myPid(),
153                             Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION));
154         }
155         if ((grantFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
156             assertEquals(PackageManager.PERMISSION_GRANTED,
157                     getContext().checkUriPermission(uri, Process.myPid(),
158                             Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
159         }
160     }
161 
waitPermissionRevoke(Uri uri, int access, long timeout)162     void waitPermissionRevoke(Uri uri, int access, long timeout) {
163         long startTime = SystemClock.elapsedRealtime();
164         while (getContext().checkUriPermission(uri, Process.myPid(), Process.myUid(), access)
165                 != PackageManager.PERMISSION_DENIED) {
166             try {
167                 Thread.sleep(50);
168             } catch (InterruptedException e) {
169             }
170             if ((SystemClock.elapsedRealtime()-startTime) >= timeout) {
171                 fail("Timed out waiting for permission revoke");
172             }
173         }
174     }
175 
176     // Note we are just using storage state as a way to control when the job gets executed.
setStorageStateLow(boolean low)177     void setStorageStateLow(boolean low) throws Exception {
178         mStorageStateChanged = true;
179         String res;
180         if (low) {
181             res = SystemUtil.runShellCommand(getInstrumentation(),
182                     "cmd devicestoragemonitor force-low -f");
183         } else {
184             res = SystemUtil.runShellCommand(getInstrumentation(),
185                     "cmd devicestoragemonitor force-not-low -f");
186         }
187         int seq = Integer.parseInt(res.trim());
188         long startTime = SystemClock.elapsedRealtime();
189 
190         // Wait for the storage update to be processed by job scheduler before proceeding.
191         int curSeq;
192         do {
193             curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
194                     "cmd jobscheduler get-storage-seq").trim());
195             if (curSeq == seq) {
196                 return;
197             }
198         } while ((SystemClock.elapsedRealtime()-startTime) < 1000);
199 
200         fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq);
201     }
202 
getJobState(int jobId)203     String getJobState(int jobId) throws Exception {
204         return SystemUtil.runShellCommand(getInstrumentation(),
205                 "cmd jobscheduler get-job-state --user cur "
206                         + kJobServiceComponent.getPackageName() + " " + jobId).trim();
207     }
208 
assertJobReady(int jobId)209     void assertJobReady(int jobId) throws Exception {
210         String state = getJobState(jobId);
211         assertTrue("Job unexpectedly not ready, in state: " + state, state.contains("ready"));
212     }
213 
assertJobWaiting(int jobId)214     void assertJobWaiting(int jobId) throws Exception {
215         String state = getJobState(jobId);
216         assertTrue("Job unexpectedly not waiting, in state: " + state, state.contains("waiting"));
217     }
218 
assertJobNotReady(int jobId)219     void assertJobNotReady(int jobId) throws Exception {
220         String state = getJobState(jobId);
221         assertTrue("Job unexpectedly ready, in state: " + state, !state.contains("ready"));
222     }
223 
224     /**
225      * Set the screen state.
226      */
toggleScreenOn(final boolean screenon)227     static void toggleScreenOn(final boolean screenon) throws Exception {
228         BatteryUtils.turnOnScreen(screenon);
229         // Wait a little bit for the broadcasts to be processed.
230         Thread.sleep(2_000);
231     }
232 
setBatteryState(boolean plugged, int level)233     void setBatteryState(boolean plugged, int level) throws Exception {
234         if (plugged) {
235             SystemUtil.runShellCommand(getInstrumentation(), "cmd battery set ac 1");
236             final int curLevel = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
237                     "dumpsys battery get level").trim());
238             if (curLevel >= level) {
239                 // Lower the level so when we set it to the desired level, JobScheduler thinks
240                 // the device is charging.
241                 SystemUtil.runShellCommand(getInstrumentation(),
242                         "cmd battery set level " + Math.max(1, level - 1));
243             }
244         } else {
245             SystemUtil.runShellCommand(getInstrumentation(), "cmd battery unplug");
246         }
247         int seq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
248                 "cmd battery set -f level " + level).trim());
249 
250         // Wait for the battery update to be processed by job scheduler before proceeding.
251         waitUntil("JobScheduler didn't update charging status to " + plugged, 15 /* seconds */,
252                 () -> {
253                     int curSeq;
254                     boolean curCharging;
255                     curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
256                             "cmd jobscheduler get-battery-seq").trim());
257                     curCharging = Boolean.parseBoolean(
258                             SystemUtil.runShellCommand(getInstrumentation(),
259                                     "cmd jobscheduler get-battery-charging").trim());
260                     return curSeq >= seq && curCharging == plugged;
261                 });
262     }
263 
264     /** Asks (not forces) JobScheduler to run the job if constraints are met. */
runSatisfiedJob(int jobId)265     void runSatisfiedJob(int jobId) throws Exception {
266         SystemUtil.runShellCommand(getInstrumentation(),
267                 "cmd jobscheduler run -s"
268                 + " -u " + UserHandle.myUserId()
269                 + " " + kJobServiceComponent.getPackageName()
270                 + " " + jobId);
271     }
272 }
273