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

Commit b55fa08c authored by Shreyas Basarge's avatar Shreyas Basarge Committed by Android (Google) Code Review
Browse files

Merge "Fixes JobScheduler not persisting flex and sourcePackage" into nyc-dev

parents 8e552f2e 8e64e2e6
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -231,10 +231,7 @@ public class JobSchedulerService extends com.android.server.SystemService
    }

    public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
        JobStatus jobStatus = new JobStatus(job, uId);
        if (packageName != null) {
            jobStatus.setSource(packageName, userId);
        }
        JobStatus jobStatus = new JobStatus(job, uId, packageName, userId);
        try {
            if (ActivityManagerNative.getDefault().getAppStartMode(uId,
                    job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
+6 −9
Original line number Diff line number Diff line
@@ -282,8 +282,7 @@ public class JobStore {
                        continue;
                    }

                    JobStatus copy = new JobStatus(jobStatus.getJob(), jobStatus.getUid(),
                            jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
                    JobStatus copy = new JobStatus(jobStatus);
                    mStoreCopy.add(copy);
                }
            }
@@ -544,7 +543,7 @@ public class JobStore {
        private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException,
                IOException {
            JobInfo.Builder jobBuilder;
            int uid, userId;
            int uid, sourceUserId;

            // Read out job identifier attributes and priority.
            try {
@@ -557,7 +556,7 @@ public class JobStore {
                    jobBuilder.setPriority(Integer.valueOf(val));
                }
                val = parser.getAttributeValue(null, "sourceUserId");
                userId = val == null ? -1 : Integer.valueOf(val);
                sourceUserId = val == null ? -1 : Integer.valueOf(val);
            } catch (NumberFormatException e) {
                Slog.e(TAG, "Error parsing job's required fields, skipping");
                return null;
@@ -608,9 +607,9 @@ public class JobStore {
                try {
                    String val = parser.getAttributeValue(null, "period");
                    final long periodMillis = Long.valueOf(val);
                    jobBuilder.setPeriodic(periodMillis);
                    val = parser.getAttributeValue(null, "flex");
                    final long flexMillis = (val != null) ? Long.valueOf(val) : periodMillis;
                    jobBuilder.setPeriodic(periodMillis, flexMillis);
                    // As a sanity check, cap the recreated run time to be no later than flex+period
                    // from now. This is the latest the periodic could be pushed out. This could
                    // happen if the periodic ran early (at flex time before period), and then the
@@ -679,10 +678,8 @@ public class JobStore {
            parser.nextTag(); // Consume </extras>

            JobStatus js = new JobStatus(
                    jobBuilder.build(), uid, elapsedRuntimes.first, elapsedRuntimes.second);
            if (userId != -1) {
                js.setSource(sourcePackageName, userId);
            }
                    jobBuilder.build(), uid, sourcePackageName, sourceUserId, elapsedRuntimes.first,
                    elapsedRuntimes.second);
            return js;
        }

+50 −45
Original line number Diff line number Diff line
@@ -48,13 +48,13 @@ public class JobStatus {

    final JobInfo job;
    /** Uid of the package requesting this job. */
    final int uId;
    final int callingUid;
    final String name;
    final String tag;

    String sourcePackageName;
    int sourceUserId = -1;
    int sourceUid = -1;
    final String sourcePackageName;
    final int sourceUserId;
    final int sourceUid;

    // Constraints.
    final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
@@ -91,30 +91,55 @@ public class JobStatus {

    /** Provide a handle to the service that this job will be run on. */
    public int getServiceToken() {
        return uId;
        return callingUid;
    }

    private JobStatus(JobInfo job, int uId, int numFailures) {
    private JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
                      int numFailures) {
        this.job = job;
        this.uId = uId;
        this.sourceUid = uId;
        this.callingUid = callingUid;
        this.name = job.getService().flattenToShortString();
        this.tag = "*job*/" + this.name;
        this.numFailures = numFailures;

        int tempSourceUid = -1;
        if (sourceUserId != -1 && sourcePackageName != null) {
            try {
                tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
                        sourceUserId);
            } catch (RemoteException ex) {
                // Can't happen, PackageManager runs in the same process.
            }
        }
        if (tempSourceUid == -1) {
            this.sourceUid = callingUid;
            this.sourceUserId = UserHandle.getUserId(callingUid);
            this.sourcePackageName = job.getService().getPackageName();
        } else {
            this.sourceUid = tempSourceUid;
            this.sourceUserId = sourceUserId;
            this.sourcePackageName = sourcePackageName;
        }
    }

    /** Copy constructor. */
    public JobStatus(JobStatus jobStatus) {
        this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getNumFailures());
        this.sourceUserId = jobStatus.sourceUserId;
        this.sourcePackageName = jobStatus.sourcePackageName;
        this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(),
                jobStatus.getSourceUserId(), jobStatus.getNumFailures());
        this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
        this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
    }

    /** Create a newly scheduled job. */
    public JobStatus(JobInfo job, int uId) {
        this(job, uId, 0);
    /**
     * Create a newly scheduled job.
     * @param callingUid Uid of the package that scheduled this job.
     * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
     *                          the calling package is the source.
     * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
     *                     calling userId.
     */
    public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId) {
        this(job, callingUid, sourcePackageName, sourceUserId, 0);

        final long elapsedNow = SystemClock.elapsedRealtime();

@@ -136,9 +161,9 @@ public class JobStatus {
     * wallclock runtime rather than resetting it on every boot.
     * We consider a freshly loaded job to no longer be in back-off.
     */
    public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis,
                      long latestRunTimeElapsedMillis) {
        this(job, uId, 0);
    public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
                     long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
        this(job, callingUid, sourcePackageName, sourceUserId, 0);

        this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
        this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
@@ -147,9 +172,8 @@ public class JobStatus {
    /** Create a new job to be rescheduled with the provided parameters. */
    public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
                      long newLatestRuntimeElapsedMillis, int backoffAttempt) {
        this(rescheduling.job, rescheduling.getUid(), backoffAttempt);
        this.sourceUserId = rescheduling.sourceUserId;
        this.sourcePackageName = rescheduling.sourcePackageName;
        this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(),
                rescheduling.getSourceUserId(), backoffAttempt);

        earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
        latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
@@ -172,7 +196,7 @@ public class JobStatus {
    }

    public String getSourcePackageName() {
        return sourcePackageName != null ? sourcePackageName : job.getService().getPackageName();
        return sourcePackageName;
    }

    public int getSourceUid() {
@@ -180,18 +204,15 @@ public class JobStatus {
    }

    public int getSourceUserId() {
        if (sourceUserId == -1) {
            sourceUserId = getUserId();
        }
        return sourceUserId;
    }

    public int getUserId() {
        return UserHandle.getUserId(uId);
        return UserHandle.getUserId(callingUid);
    }

    public int getUid() {
        return uId;
        return callingUid;
    }

    public String getName() {
@@ -278,7 +299,7 @@ public class JobStatus {
    }

    public boolean matches(int uid, int jobId) {
        return this.job.getId() == jobId && this.uId == uid;
        return this.job.getId() == jobId && this.callingUid == uid;
    }

    @Override
@@ -312,22 +333,6 @@ public class JobStatus {
        }
    }

    public void setSource(String sourcePackageName, int sourceUserId) {
        this.sourcePackageName = sourcePackageName;
        this.sourceUserId = sourceUserId;
        try {
            sourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
                    sourceUserId);
        } catch (RemoteException ex) {
            // Can't happen, PackageManager runs in the same process.
        }
        if (sourceUid == -1) {
            sourceUid = uId;
            this.sourceUserId = getUserId();
            this.sourcePackageName = null;
        }
    }

    /**
     * Convenience function to identify a job uniquely without pulling all the data that
     * {@link #toString()} returns.
@@ -338,7 +343,7 @@ public class JobStatus {
        sb.append(" jId=");
        sb.append(job.getId());
        sb.append(" uid=");
        UserHandle.formatUid(sb, uId);
        UserHandle.formatUid(sb, callingUid);
        sb.append(' ');
        sb.append(job.getService().flattenToShortString());
        return sb.toString();
@@ -346,7 +351,7 @@ public class JobStatus {

    // Dumpsys infrastructure
    public void dump(PrintWriter pw, String prefix) {
        pw.print(prefix); UserHandle.formatUid(pw, uId);
        pw.print(prefix); UserHandle.formatUid(pw, callingUid);
        pw.print(" tag="); pw.println(tag);
        pw.print(prefix);
        pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
+57 −15
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ public class JobStoreTest extends AndroidTestCase {
                .setMinimumLatency(runFromMillis)
                .setPersisted(true)
                .build();
        final JobStatus ts = new JobStatus(task, SOME_UID);
        final JobStatus ts = new JobStatus(task, SOME_UID, null, -1);
        mTaskStoreUnderTest.add(ts);
        Thread.sleep(IO_WAIT);
        // Manually load tasks from xml file.
@@ -91,8 +91,8 @@ public class JobStoreTest extends AndroidTestCase {
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
                .setPersisted(true)
                .build();
        final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID);
        final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID);
        final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID, null, -1);
        final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID, null, -1);
        mTaskStoreUnderTest.add(taskStatus1);
        mTaskStoreUnderTest.add(taskStatus2);
        Thread.sleep(IO_WAIT);
@@ -140,7 +140,7 @@ public class JobStoreTest extends AndroidTestCase {
        extras.putInt("into", 3);
        b.setExtras(extras);
        final JobInfo task = b.build();
        JobStatus taskStatus = new JobStatus(task, SOME_UID);
        JobStatus taskStatus = new JobStatus(task, SOME_UID, null, -1);

        mTaskStoreUnderTest.add(taskStatus);
        Thread.sleep(IO_WAIT);
@@ -151,17 +151,59 @@ public class JobStoreTest extends AndroidTestCase {
        JobStatus loaded = jobStatusSet.iterator().next();
        assertTasksEqual(task, loaded.getJob());
    }
    public void testWritingTaskWithSourcePackage() throws Exception {
        JobInfo.Builder b = new Builder(8, mComponent)
                .setRequiresDeviceIdle(true)
                .setPeriodic(10000L)
                .setRequiresCharging(true)
                .setPersisted(true);
        JobStatus taskStatus = new JobStatus(b.build(), SOME_UID, "com.google.android.gms", 0);

        mTaskStoreUnderTest.add(taskStatus);
        Thread.sleep(IO_WAIT);

        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
        JobStatus loaded = jobStatusSet.iterator().next();
        assertEquals("Source package not equal.", loaded.getSourcePackageName(),
                taskStatus.getSourcePackageName());
        assertEquals("Source user not equal.", loaded.getSourceUserId(),
                taskStatus.getSourceUserId());
    }

    public void testWritingTaskWithFlex() throws Exception {
        JobInfo.Builder b = new Builder(8, mComponent)
                .setRequiresDeviceIdle(true)
                .setPeriodic(5*60*60*1000, 1*60*60*1000)
                .setRequiresCharging(true)
                .setPersisted(true);
        JobStatus taskStatus = new JobStatus(b.build(), SOME_UID, null, -1);

        mTaskStoreUnderTest.add(taskStatus);
        Thread.sleep(IO_WAIT);

        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
        assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
        JobStatus loaded = jobStatusSet.iterator().next();
        assertEquals("Period not equal.", loaded.getJob().getIntervalMillis(),
                taskStatus.getJob().getIntervalMillis());
        assertEquals("Flex not equal.", loaded.getJob().getFlexMillis(),
                taskStatus.getJob().getFlexMillis());
    }

    public void testMassivePeriodClampedOnRead() throws Exception {
        final long TEN_SECONDS = 10000L;
        final long ONE_HOUR = 60*60*1000L; // flex
        final long TWO_HOURS = 2 * ONE_HOUR; // period
        JobInfo.Builder b = new Builder(8, mComponent)
                .setPeriodic(TEN_SECONDS)
                .setPeriodic(TWO_HOURS, ONE_HOUR)
                .setPersisted(true);
        final long invalidLateRuntimeElapsedMillis =
                SystemClock.elapsedRealtime() + (TEN_SECONDS * 2) + 5000;  // >2P from now.
                SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS;  // > period+flex
        final long invalidEarlyRuntimeElapsedMillis =
                invalidLateRuntimeElapsedMillis - TEN_SECONDS;  // Early is (late - period).
        final JobStatus js = new JobStatus(b.build(), SOME_UID,
                invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
        final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage", 0 /* sourceUserId */,
                invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);

        mTaskStoreUnderTest.add(js);
@@ -176,10 +218,10 @@ public class JobStoreTest extends AndroidTestCase {
        // call SystemClock.elapsedRealtime after doing the disk i/o.
        final long newNowElapsed = SystemClock.elapsedRealtime();
        assertTrue("Early runtime wasn't correctly clamped.",
                loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS);
        // Assert late runtime was clamped to be now + period*2.
                loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS);
        // Assert late runtime was clamped to be now + period + flex.
        assertTrue("Early runtime wasn't correctly clamped.",
                loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS * 2);
                loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS + ONE_HOUR);
    }

    public void testPriorityPersisted() throws Exception {
@@ -187,7 +229,7 @@ public class JobStoreTest extends AndroidTestCase {
                .setOverrideDeadline(5000)
                .setPriority(42)
                .setPersisted(true);
        final JobStatus js = new JobStatus(b.build(), SOME_UID);
        final JobStatus js = new JobStatus(b.build(), SOME_UID, null, -1);
        mTaskStoreUnderTest.add(js);
        Thread.sleep(IO_WAIT);
        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
@@ -203,12 +245,12 @@ public class JobStoreTest extends AndroidTestCase {
        JobInfo.Builder b = new Builder(42, mComponent)
                .setOverrideDeadline(10000)
                .setPersisted(false);
        JobStatus jsNonPersisted = new JobStatus(b.build(), SOME_UID);
        JobStatus jsNonPersisted = new JobStatus(b.build(), SOME_UID, null, -1);
        mTaskStoreUnderTest.add(jsNonPersisted);
        b = new Builder(43, mComponent)
                .setOverrideDeadline(10000)
                .setPersisted(true);
        JobStatus jsPersisted = new JobStatus(b.build(), SOME_UID);
        JobStatus jsPersisted = new JobStatus(b.build(), SOME_UID, null, -1);
        mTaskStoreUnderTest.add(jsPersisted);
        Thread.sleep(IO_WAIT);
        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();