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

Commit 9ae3dbee authored by Matthew Williams's avatar Matthew Williams
Browse files

JobScheduler only run jobs for started users.

BUG: 12876556
Minor changes to test app to make persisting an option.
Change-Id: I1b40347878ec5ca44cd717ebfeb544f6c58473b5
parent bfecd904
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -26,6 +26,9 @@ import android.os.PersistableBundle;
 * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
 * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
 * parameters required to schedule work against the calling application. These are constructed
 * parameters required to schedule work against the calling application. These are constructed
 * using the {@link JobInfo.Builder}.
 * using the {@link JobInfo.Builder}.
 * You must specify at least one sort of constraint on the JobInfo object that you are creating.
 * The goal here is to provide the scheduler with high-level semantics about the work you want to
 * accomplish. Doing otherwise with throw an exception in your app.
 */
 */
public class JobInfo implements Parcelable {
public class JobInfo implements Parcelable {
    public interface NetworkType {
    public interface NetworkType {
@@ -434,7 +437,7 @@ public class JobInfo implements Parcelable {
         * @return The job object to hand to the JobScheduler. This object is immutable.
         * @return The job object to hand to the JobScheduler. This object is immutable.
         */
         */
        public JobInfo build() {
        public JobInfo build() {
            // Allow tasks with no constraints. What am I, a database?
            // Allow jobs with no constraints - What am I, a database?
            if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
            if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
                    !mRequiresDeviceIdle && mNetworkCapabilities == NetworkType.NONE) {
                    !mRequiresDeviceIdle && mNetworkCapabilities == NetworkType.NONE) {
                throw new IllegalArgumentException("You're trying to build a job with no " +
                throw new IllegalArgumentException("You're trying to build a job with no " +
+31 −1
Original line number Original line Diff line number Diff line
@@ -117,6 +117,8 @@ public class JobSchedulerService extends com.android.server.SystemService
     */
     */
    final ArrayList<JobStatus> mPendingJobs = new ArrayList<JobStatus>();
    final ArrayList<JobStatus> mPendingJobs = new ArrayList<JobStatus>();


    final ArrayList<Integer> mStartedUsers = new ArrayList();

    final JobHandler mHandler;
    final JobHandler mHandler;
    final JobSchedulerStub mJobSchedulerStub;
    final JobSchedulerStub mJobSchedulerStub;


@@ -151,6 +153,18 @@ public class JobSchedulerService extends com.android.server.SystemService
        }
        }
    };
    };


    @Override
    public void onStartUser(int userHandle) {
        mStartedUsers.add(userHandle);
        // Let's kick any outstanding jobs for this user.
        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
    }

    @Override
    public void onStopUser(int userHandle) {
        mStartedUsers.remove(Integer.valueOf(userHandle));
    }

    /**
    /**
     * Entry point from client to schedule the provided job.
     * Entry point from client to schedule the provided job.
     * This cancels the job if it's already been scheduled, and replaces it with the one provided.
     * This cancels the job if it's already been scheduled, and replaces it with the one provided.
@@ -610,9 +624,20 @@ public class JobSchedulerService extends com.android.server.SystemService
         *      - It's ready.
         *      - It's ready.
         *      - It's not pending.
         *      - It's not pending.
         *      - It's not already running on a JSC.
         *      - It's not already running on a JSC.
         *      - The user that requested the job is running.
         */
         */
        private boolean isReadyToBeExecutedLocked(JobStatus job) {
        private boolean isReadyToBeExecutedLocked(JobStatus job) {
              return job.isReady() && !mPendingJobs.contains(job) && !isCurrentlyActiveLocked(job);
            final boolean jobReady = job.isReady();
            final boolean jobPending = mPendingJobs.contains(job);
            final boolean jobActive = isCurrentlyActiveLocked(job);
            final boolean userRunning = mStartedUsers.contains(job.getUserId());

            if (DEBUG) {
                Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
                        + " ready=" + jobReady + " pending=" + jobPending
                        + " active=" + jobActive + " userRunning=" + userRunning);
            }
            return userRunning && jobReady && !jobPending && !jobActive;
        }
        }


        /**
        /**
@@ -795,6 +820,11 @@ public class JobSchedulerService extends com.android.server.SystemService


    void dumpInternal(PrintWriter pw) {
    void dumpInternal(PrintWriter pw) {
        synchronized (mJobs) {
        synchronized (mJobs) {
            pw.print("Started users: ");
            for (int i=0; i<mStartedUsers.size(); i++) {
                pw.print("u" + mStartedUsers.get(i) + " ");
            }
            pw.println();
            pw.println("Registered jobs:");
            pw.println("Registered jobs:");
            if (mJobs.size() > 0) {
            if (mJobs.size() > 0) {
                ArraySet<JobStatus> jobs = mJobs.getJobs();
                ArraySet<JobStatus> jobs = mJobs.getJobs();
+30 −1
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.ComponentName;
import android.os.PersistableBundle;
import android.os.PersistableBundle;
import android.os.SystemClock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserHandle;
import android.text.format.DateUtils;


import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -41,6 +42,7 @@ public class JobStatus {
    public static final long NO_EARLIEST_RUNTIME = 0L;
    public static final long NO_EARLIEST_RUNTIME = 0L;


    final JobInfo job;
    final JobInfo job;
    /** Uid of the package requesting this job. */
    final int uId;
    final int uId;
    final String name;
    final String name;
    final String tag;
    final String tag;
@@ -214,12 +216,39 @@ public class JobStatus {
        return String.valueOf(hashCode()).substring(0, 3) + ".."
        return String.valueOf(hashCode()).substring(0, 3) + ".."
                + ":[" + job.getService()
                + ":[" + job.getService()
                + ",jId=" + job.getId()
                + ",jId=" + job.getId()
                + ",R=(" + earliestRunTimeElapsedMillis + "," + latestRunTimeElapsedMillis + ")"
                + ",u" + getUserId()
                + ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
                + "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
                + ",N=" + job.getNetworkCapabilities() + ",C=" + job.isRequireCharging()
                + ",N=" + job.getNetworkCapabilities() + ",C=" + job.isRequireCharging()
                + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
                + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
                + ",P=" + job.isPersisted()
                + (isReady() ? "(READY)" : "")
                + (isReady() ? "(READY)" : "")
                + "]";
                + "]";
    }
    }

    private String formatRunTime(long runtime, long  defaultValue) {
        if (runtime == defaultValue) {
            return "none";
        } else {
            long elapsedNow = SystemClock.elapsedRealtime();
            long nextRuntime = runtime - elapsedNow;
            if (nextRuntime > 0) {
                return DateUtils.formatElapsedTime(nextRuntime / 1000);
            } else {
                return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000);
            }
        }
    }

    /**
     * Convenience function to identify a job uniquely without pulling all the data that
     * {@link #toString()} returns.
     */
    public String toShortString() {
        return job.getService().flattenToShortString() + " jId=" + job.getId() +
                ", u" + getUserId();
    }

    // Dumpsys infrastructure
    // Dumpsys infrastructure
    public void dump(PrintWriter pw, String prefix) {
    public void dump(PrintWriter pw, String prefix) {
        pw.println(this.toString());
        pw.println(this.toString());
+14 −0
Original line number Original line Diff line number Diff line
@@ -141,6 +141,20 @@
                        android:id="@+id/checkbox_idle"
                        android:id="@+id/checkbox_idle"
                        android:text="@string/idle_mode_text"/>
                        android:text="@string/idle_mode_text"/>
                </LinearLayout>
                </LinearLayout>
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/persisted_caption"
                        android:layout_marginRight="15dp"/>
                    <CheckBox
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:id="@+id/checkbox_persisted"
                        android:text="@string/persisted_mode_text"/>
                </LinearLayout>


            </LinearLayout>
            </LinearLayout>
        <Button
        <Button
+2 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ limitations under the License.
    <string name="charging_caption">Charging:</string>
    <string name="charging_caption">Charging:</string>
    <string name="charging_text">Requires device plugged in.</string>
    <string name="charging_text">Requires device plugged in.</string>
    <string name="idle_caption">Idle:</string>
    <string name="idle_caption">Idle:</string>
    <string name="persisted_caption">Persisted:</string>
    <string name="constraints">Constraints</string>
    <string name="constraints">Constraints</string>
    <string name="connectivity">Connectivity:</string>
    <string name="connectivity">Connectivity:</string>
    <string name="any">Any</string>
    <string name="any">Any</string>
@@ -34,4 +35,5 @@ limitations under the License.
    <string name="timing">Timing:</string>
    <string name="timing">Timing:</string>
    <string name="delay">Delay:</string>
    <string name="delay">Delay:</string>
    <string name="deadline">Deadline:</string>
    <string name="deadline">Deadline:</string>
    <string name="persisted_mode_text">Persisted:</string>
</resources>
</resources>
Loading