blob: 8db459e1475d54c7ecccd13599f57a2af1c99c9c [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.jobscheduler.cts;
import static android.app.ActivityManager.getCapabilitiesSummary;
import static android.app.ActivityManager.procStateToString;
import static android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver.EXTRA_REQUEST_JOB_UID_STATE;
import static android.jobscheduler.cts.jobtestapp.TestJobService.ACTION_JOB_STARTED;
import static android.jobscheduler.cts.jobtestapp.TestJobService.ACTION_JOB_STOPPED;
import static android.jobscheduler.cts.jobtestapp.TestJobService.INVALID_ADJ;
import static android.jobscheduler.cts.jobtestapp.TestJobService.JOB_CAPABILITIES_KEY;
import static android.jobscheduler.cts.jobtestapp.TestJobService.JOB_OOM_SCORE_ADJ_KEY;
import static android.jobscheduler.cts.jobtestapp.TestJobService.JOB_PARAMS_EXTRA_KEY;
import static android.jobscheduler.cts.jobtestapp.TestJobService.JOB_PROC_STATE_KEY;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
import static org.junit.Assert.assertEquals;
import android.app.ActivityManager;
import android.app.job.JobParameters;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.jobscheduler.cts.jobtestapp.TestActivity;
import android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver;
import android.os.SystemClock;
import android.os.UserHandle;
import android.server.wm.WindowManagerStateHelper;
import android.util.Log;
import com.android.compatibility.common.util.CallbackAsserter;
import com.android.compatibility.common.util.SystemUtil;
import java.util.Map;
/**
* Common functions to interact with the test app.
*/
class TestAppInterface {
private static final String TAG = TestAppInterface.class.getSimpleName();
static final String TEST_APP_PACKAGE = "android.jobscheduler.cts.jobtestapp";
private static final String TEST_APP_ACTIVITY = TEST_APP_PACKAGE + ".TestActivity";
static final String TEST_APP_RECEIVER = TEST_APP_PACKAGE + ".TestJobSchedulerReceiver";
private final Context mContext;
private final int mJobId;
/* accesses must be synchronized on itself */
private final TestJobState mTestJobState = new TestJobState();
TestAppInterface(Context ctx, int jobId) {
mContext = ctx;
mJobId = jobId;
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_JOB_STARTED);
intentFilter.addAction(ACTION_JOB_STOPPED);
mContext.registerReceiver(mReceiver, intentFilter);
}
void cleanup() {
final Intent cancelJobsIntent = new Intent(TestJobSchedulerReceiver.ACTION_CANCEL_JOBS);
cancelJobsIntent.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_RECEIVER));
cancelJobsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.sendBroadcast(cancelJobsIntent);
closeActivity();
mContext.unregisterReceiver(mReceiver);
mTestJobState.reset();
}
void scheduleJob(boolean allowWhileIdle, int requiredNetworkType, boolean asExpeditedJob)
throws Exception {
scheduleJob(
Map.of(
TestJobSchedulerReceiver.EXTRA_ALLOW_IN_IDLE, allowWhileIdle,
TestJobSchedulerReceiver.EXTRA_AS_EXPEDITED, asExpeditedJob
),
Map.of(
TestJobSchedulerReceiver.EXTRA_REQUIRED_NETWORK_TYPE, requiredNetworkType
));
}
void scheduleJob(Map<String, Boolean> booleanExtras, Map<String, Integer> intExtras)
throws Exception {
final Intent scheduleJobIntent = new Intent(TestJobSchedulerReceiver.ACTION_SCHEDULE_JOB);
scheduleJobIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
scheduleJobIntent.putExtra(TestJobSchedulerReceiver.EXTRA_JOB_ID_KEY, mJobId);
booleanExtras.forEach(scheduleJobIntent::putExtra);
intExtras.forEach(scheduleJobIntent::putExtra);
scheduleJobIntent.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_RECEIVER));
final CallbackAsserter resultBroadcastAsserter = CallbackAsserter.forBroadcast(
new IntentFilter(TestJobSchedulerReceiver.ACTION_JOB_SCHEDULE_RESULT));
mContext.sendBroadcast(scheduleJobIntent);
resultBroadcastAsserter.assertCalled("Didn't get schedule job result broadcast",
15 /* 15 seconds */);
}
/** Asks (not forces) JobScheduler to run the job if constraints are met. */
void runSatisfiedJob() throws Exception {
SystemUtil.runShellCommand("cmd jobscheduler run -s"
+ " -u " + UserHandle.myUserId() + " " + TEST_APP_PACKAGE + " " + mJobId);
}
void startAndKeepTestActivity() {
startAndKeepTestActivity(false);
}
void startAndKeepTestActivity(boolean waitForResume) {
final Intent testActivity = new Intent();
testActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName testComponentName = new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY);
testActivity.setComponent(testComponentName);
mContext.startActivity(testActivity);
if (waitForResume) {
new WindowManagerStateHelper().waitForActivityState(testComponentName, STATE_RESUMED);
}
}
void closeActivity() {
mContext.sendBroadcast(new Intent(TestActivity.ACTION_FINISH_ACTIVITY));
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received action " + intent.getAction());
switch (intent.getAction()) {
case ACTION_JOB_STARTED:
case ACTION_JOB_STOPPED:
final JobParameters params = intent.getParcelableExtra(JOB_PARAMS_EXTRA_KEY);
Log.d(TAG, "JobId: " + params.getJobId());
synchronized (mTestJobState) {
mTestJobState.running = ACTION_JOB_STARTED.equals(intent.getAction());
mTestJobState.jobId = params.getJobId();
mTestJobState.params = params;
if (intent.getBooleanExtra(EXTRA_REQUEST_JOB_UID_STATE, false)) {
mTestJobState.procState = intent.getIntExtra(JOB_PROC_STATE_KEY,
ActivityManager.PROCESS_STATE_NONEXISTENT);
mTestJobState.capabilities = intent.getIntExtra(JOB_CAPABILITIES_KEY,
ActivityManager.PROCESS_CAPABILITY_NONE);
mTestJobState.oomScoreAdj = intent.getIntExtra(JOB_OOM_SCORE_ADJ_KEY,
INVALID_ADJ);
}
}
break;
}
}
};
boolean awaitJobStart(long maxWait) throws Exception {
return waitUntilTrue(maxWait, () -> {
synchronized (mTestJobState) {
return (mTestJobState.jobId == mJobId) && mTestJobState.running;
}
});
}
boolean awaitJobStop(long maxWait) throws Exception {
return waitUntilTrue(maxWait, () -> {
synchronized (mTestJobState) {
return (mTestJobState.jobId == mJobId) && !mTestJobState.running;
}
});
}
void assertJobUidState(int procState, int capabilities, int oomScoreAdj) {
synchronized (mTestJobState) {
assertEquals("procState expected=" + procStateToString(procState)
+ ",actual=" + procStateToString(mTestJobState.procState),
procState, mTestJobState.procState);
assertEquals("capabilities expected=" + getCapabilitiesSummary(capabilities)
+ ",actual=" + getCapabilitiesSummary(mTestJobState.capabilities),
capabilities, mTestJobState.capabilities);
assertEquals("Unexpected oomScoreAdj", oomScoreAdj, mTestJobState.oomScoreAdj);
}
}
private boolean waitUntilTrue(long maxWait, Condition condition) throws Exception {
final long deadLine = SystemClock.uptimeMillis() + maxWait;
do {
Thread.sleep(500);
} while (!condition.isTrue() && SystemClock.uptimeMillis() < deadLine);
return condition.isTrue();
}
JobParameters getLastParams() {
synchronized (mTestJobState) {
return mTestJobState.params;
}
}
private static final class TestJobState {
int jobId;
boolean running;
int procState;
int capabilities;
int oomScoreAdj;
JobParameters params;
TestJobState() {
initState();
}
private void reset() {
initState();
}
private void initState() {
running = false;
procState = ActivityManager.PROCESS_STATE_NONEXISTENT;
capabilities = ActivityManager.PROCESS_CAPABILITY_NONE;
oomScoreAdj = INVALID_ADJ;
}
}
private interface Condition {
boolean isTrue() throws Exception;
}
}