Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7ac76f7 authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Fixing job scheduler test flakiness

Adding a deadline to the test job since timing delay alone can defer the
job indefinitely.
Since deadline is dropped for reschedules, using a new job every time
the job is stopped.

Test: atest FrameworksServicesTests:BackgroundRestrictionsTest

Fixes: 172318004
Change-Id: Ib757def409b4af34fb51ab13e06a38e207d3b332
parent ccd734ac
Loading
Loading
Loading
Loading
+32 −18
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ import android.provider.Settings;
import android.util.Log;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;

@@ -61,7 +60,7 @@ import org.junit.runner.RunWith;
 *  adb install -r $OUT/data/app/JobTestApp/JobTestApp.apk
 *  adb install -r $OUT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
 *  adb  shell am instrument -e class 'com.android.server.job.BackgroundRestrictionsTest' -w \
    com.android.frameworks.servicestests
 *  com.android.frameworks.servicestests
 * </pre>
 */
@RunWith(AndroidJUnit4.class)
@@ -70,14 +69,14 @@ public class BackgroundRestrictionsTest {
    private static final String TAG = BackgroundRestrictionsTest.class.getSimpleName();
    private static final String TEST_APP_PACKAGE = "com.android.servicestests.apps.jobtestapp";
    private static final String TEST_APP_ACTIVITY = TEST_APP_PACKAGE + ".TestJobActivity";
    private static final long POLL_INTERVAL = 2000;
    private static final long POLL_INTERVAL = 500;
    private static final long DEFAULT_WAIT_TIMEOUT = 5000;

    private Context mContext;
    private AppOpsManager mAppOpsManager;
    private IDeviceIdleController mDeviceIdleController;
    private IActivityManager mIActivityManager;
    private int mTestJobId;
    private volatile int mTestJobId = -1;
    private int mTestPackageUid;
    /* accesses must be synchronized on itself */
    private final TestJobStatus mTestJobStatus = new TestJobStatus();
@@ -111,40 +110,54 @@ public class BackgroundRestrictionsTest {
                ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
        mIActivityManager = ActivityManager.getService();
        mTestPackageUid = mContext.getPackageManager().getPackageUid(TEST_APP_PACKAGE, 0);
        mTestJobId = (int) (SystemClock.uptimeMillis() / 1000);
        mTestJobStatus.reset();
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_JOB_STARTED);
        intentFilter.addAction(ACTION_JOB_STOPPED);
        mContext.registerReceiver(mJobStateChangeReceiver, intentFilter);
        setAppOpsModeAllowed(true);
        setPowerWhiteListed(false);
        setPowerExemption(false);
    }

    private void scheduleAndAssertJobStarted() throws Exception {
    private void scheduleTestJob() {
        mTestJobId = (int) (SystemClock.uptimeMillis() / 1000);
        final Intent scheduleJobIntent = new Intent(TestJobActivity.ACTION_START_JOB);
        scheduleJobIntent.putExtra(TestJobActivity.EXTRA_JOB_ID_KEY, mTestJobId);
        scheduleJobIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        scheduleJobIntent.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY));
        mContext.startActivity(scheduleJobIntent);
    }

    private void scheduleAndAssertJobStarted() throws Exception {
        scheduleTestJob();
        Thread.sleep(TestJobActivity.JOB_MINIMUM_LATENCY);
        assertTrue("Job did not start after scheduling", awaitJobStart(DEFAULT_WAIT_TIMEOUT));
    }

    @Test
    @FlakyTest
    public void testPowerWhiteList() throws Exception {
    public void testPowerExemption() throws Exception {
        scheduleAndAssertJobStarted();
        setAppOpsModeAllowed(false);
        mIActivityManager.makePackageIdle(TEST_APP_PACKAGE, UserHandle.USER_CURRENT);
        assertTrue("Job did not stop after making idle", awaitJobStop(DEFAULT_WAIT_TIMEOUT));
        setPowerWhiteListed(true);
        Thread.sleep(TestJobActivity.JOB_INITIAL_BACKOFF);
        assertTrue("Job did not start after adding to power whitelist",
        assertTrue("Job did not stop after putting app under bg-restriction",
                awaitJobStop(DEFAULT_WAIT_TIMEOUT));

        setPowerExemption(true);
        scheduleTestJob();
        Thread.sleep(TestJobActivity.JOB_MINIMUM_LATENCY);
        assertTrue("Job did not start when the app was in the power exemption list",
                awaitJobStart(DEFAULT_WAIT_TIMEOUT));
        setPowerWhiteListed(false);
        assertTrue("Job did not stop after removing from power whitelist",

        setPowerExemption(false);
        assertTrue("Job did not stop after removing from the power exemption list",
                awaitJobStop(DEFAULT_WAIT_TIMEOUT));

        scheduleTestJob();
        Thread.sleep(TestJobActivity.JOB_MINIMUM_LATENCY);
        assertFalse("Job started under bg-restrictions", awaitJobStart(DEFAULT_WAIT_TIMEOUT));
        setPowerExemption(true);
        assertTrue("Job did not start when the app was in the power exemption list",
                awaitJobStart(DEFAULT_WAIT_TIMEOUT));
    }

    @Test
@@ -167,13 +180,13 @@ public class BackgroundRestrictionsTest {
        mContext.unregisterReceiver(mJobStateChangeReceiver);
        Thread.sleep(500); // To avoid race with register in the next setUp
        setAppOpsModeAllowed(true);
        setPowerWhiteListed(false);
        setPowerExemption(false);
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.FORCED_APP_STANDBY_ENABLED, 1);
    }

    private void setPowerWhiteListed(boolean whitelist) throws RemoteException {
        if (whitelist) {
    private void setPowerExemption(boolean exempt) throws RemoteException {
        if (exempt) {
            mDeviceIdleController.addPowerSaveWhitelistApp(TEST_APP_PACKAGE);
        } else {
            mDeviceIdleController.removePowerSaveWhitelistApp(TEST_APP_PACKAGE);
@@ -214,6 +227,7 @@ public class BackgroundRestrictionsTest {
        int jobId;
        int stopReason;
        boolean running;

        private void reset() {
            running = false;
            stopReason = jobId = 0;
+2 −1
Original line number Diff line number Diff line
@@ -50,7 +50,8 @@ public class TestJobActivity extends Activity {
                final int jobId = intent.getIntExtra(EXTRA_JOB_ID_KEY, hashCode());
                JobInfo.Builder jobBuilder = new JobInfo.Builder(jobId, jobServiceComponent)
                        .setBackoffCriteria(JOB_INITIAL_BACKOFF, JobInfo.BACKOFF_POLICY_LINEAR)
                        .setMinimumLatency(JOB_MINIMUM_LATENCY);
                        .setMinimumLatency(JOB_MINIMUM_LATENCY)
                        .setOverrideDeadline(JOB_MINIMUM_LATENCY);
                final int result = jobScheduler.schedule(jobBuilder.build());
                if (result != JobScheduler.RESULT_SUCCESS) {
                    Log.e(TAG, "Could not schedule job " + jobId);
+2 −1
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ public class TestJobService extends JobService {
        Intent reportJobStopIntent = new Intent(ACTION_JOB_STOPPED);
        reportJobStopIntent.putExtra(JOB_PARAMS_EXTRA_KEY, params);
        sendBroadcast(reportJobStopIntent);
        return true;
        // Deadline constraint is dropped on reschedule, so it's more reliable to use a new job.
        return false;
    }
}