• 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 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     /** Environment that notifies of JobScheduler callbacks. */
45     static MockJobService.TestEnvironment kTestEnvironment =
46             MockJobService.TestEnvironment.getTestEnvironment();
47     static TriggerContentJobService.TestEnvironment kTriggerTestEnvironment =
48             TriggerContentJobService.TestEnvironment.getTestEnvironment();
49     /** Handle for the service which receives the execution callbacks from the JobScheduler. */
50     static ComponentName kJobServiceComponent;
51     static ComponentName kTriggerContentServiceComponent;
52     JobScheduler mJobScheduler;
53 
54     Context mContext;
55 
56     static final String MY_PACKAGE = "android.jobscheduler.cts";
57 
58     static final String JOBPERM_PACKAGE = "android.jobscheduler.cts.jobperm";
59     static final String JOBPERM_AUTHORITY = "android.jobscheduler.cts.jobperm.provider";
60     static final String JOBPERM_PERM = "android.jobscheduler.cts.jobperm.perm";
61 
62     Uri mFirstUri;
63     Bundle mFirstUriBundle;
64     Uri mSecondUri;
65     Bundle mSecondUriBundle;
66     ClipData mFirstClipData;
67     ClipData mSecondClipData;
68 
69     boolean mStorageStateChanged;
70 
71     @Override
injectInstrumentation(Instrumentation instrumentation)72     public void injectInstrumentation(Instrumentation instrumentation) {
73         super.injectInstrumentation(instrumentation);
74         mContext = instrumentation.getContext();
75         kJobServiceComponent = new ComponentName(getContext(), MockJobService.class);
76         kTriggerContentServiceComponent = new ComponentName(getContext(),
77                 TriggerContentJobService.class);
78         mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
79         mFirstUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/foo");
80         mFirstUriBundle = new Bundle();
81         mFirstUriBundle.putParcelable("uri", mFirstUri);
82         mSecondUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/bar");
83         mSecondUriBundle = new Bundle();
84         mSecondUriBundle.putParcelable("uri", mSecondUri);
85         mFirstClipData = new ClipData("JobPerm1", new String[] { "application/*" },
86                 new ClipData.Item(mFirstUri));
87         mSecondClipData = new ClipData("JobPerm2", new String[] { "application/*" },
88                 new ClipData.Item(mSecondUri));
89         try {
90             SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
91                     + mContext.getPackageName() + " false");
92         } catch (IOException e) {
93             Log.w("ConstraintTest", "Failed setting inactive false", e);
94         }
95     }
96 
getContext()97     public Context getContext() {
98         return mContext;
99     }
100 
101     @Override
setUp()102     public void setUp() throws Exception {
103         super.setUp();
104         kTestEnvironment.setUp();
105         kTriggerTestEnvironment.setUp();
106         mJobScheduler.cancelAll();
107     }
108 
109     @Override
tearDown()110     public void tearDown() throws Exception {
111         SystemUtil.runShellCommand(getInstrumentation(), "cmd battery reset");
112         if (mStorageStateChanged) {
113             // Put storage service back in to normal operation.
114             SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset");
115             mStorageStateChanged = false;
116         }
117 
118         // The super method should be called at the end.
119         super.tearDown();
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      */
sendExpediteStableChargingBroadcast()127     protected void sendExpediteStableChargingBroadcast() throws IOException {
128         // Faking the device to be 90% charging and then to be 91%, so that it triggers
129         // BatteryManager.ACTION_CHARGING in the upward change-level transition logic.
130         SystemUtil.runShellCommand(getInstrumentation(), "cmd battery set level 90");
131         SystemUtil.runShellCommand(getInstrumentation(), "cmd battery set level 91");
132     }
133 
assertHasUriPermission(Uri uri, int grantFlags)134     public void assertHasUriPermission(Uri uri, int grantFlags) {
135         if ((grantFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
136             assertEquals(PackageManager.PERMISSION_GRANTED,
137                     getContext().checkUriPermission(uri, Process.myPid(),
138                             Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION));
139         }
140         if ((grantFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
141             assertEquals(PackageManager.PERMISSION_GRANTED,
142                     getContext().checkUriPermission(uri, Process.myPid(),
143                             Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
144         }
145     }
146 
waitPermissionRevoke(Uri uri, int access, long timeout)147     void waitPermissionRevoke(Uri uri, int access, long timeout) {
148         long startTime = SystemClock.elapsedRealtime();
149         while (getContext().checkUriPermission(uri, Process.myPid(), Process.myUid(), access)
150                 != PackageManager.PERMISSION_DENIED) {
151             try {
152                 Thread.sleep(50);
153             } catch (InterruptedException e) {
154             }
155             if ((SystemClock.elapsedRealtime()-startTime) >= timeout) {
156                 fail("Timed out waiting for permission revoke");
157             }
158         }
159     }
160 
161     // Note we are just using storage state as a way to control when the job gets executed.
setStorageState(boolean low)162     void setStorageState(boolean low) throws Exception {
163         mStorageStateChanged = true;
164         String res;
165         if (low) {
166             res = SystemUtil.runShellCommand(getInstrumentation(),
167                     "cmd devicestoragemonitor force-low -f");
168         } else {
169             res = SystemUtil.runShellCommand(getInstrumentation(),
170                     "cmd devicestoragemonitor force-not-low -f");
171         }
172         int seq = Integer.parseInt(res.trim());
173         long startTime = SystemClock.elapsedRealtime();
174 
175         // Wait for the storage update to be processed by job scheduler before proceeding.
176         int curSeq;
177         do {
178             curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
179                     "cmd jobscheduler get-storage-seq").trim());
180             if (curSeq == seq) {
181                 return;
182             }
183         } while ((SystemClock.elapsedRealtime()-startTime) < 1000);
184 
185         fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq);
186     }
187 
getJobState(int jobId)188     String getJobState(int jobId) throws Exception {
189         return SystemUtil.runShellCommand(getInstrumentation(),
190                 "cmd jobscheduler get-job-state --user cur "
191                         + kJobServiceComponent.getPackageName() + " " + jobId).trim();
192     }
193 
assertJobReady(int jobId)194     void assertJobReady(int jobId) throws Exception {
195         String state = getJobState(jobId);
196         assertTrue("Job unexpectedly not ready, in state: " + state, state.contains("ready"));
197     }
198 
assertJobWaiting(int jobId)199     void assertJobWaiting(int jobId) throws Exception {
200         String state = getJobState(jobId);
201         assertTrue("Job unexpectedly not waiting, in state: " + state, state.contains("waiting"));
202     }
203 
assertJobNotReady(int jobId)204     void assertJobNotReady(int jobId) throws Exception {
205         String state = getJobState(jobId);
206         assertTrue("Job unexpectedly ready, in state: " + state, !state.contains("ready"));
207     }
208 }
209