Work towards issue #26390161: Throttle syncs/jobs when system is low on RAM

First, we need to make the job scheduler prioritize jobs for
foreground apps over background apps (so we will degrade well
when we are limiting the number of concurrent jobs).

So now the job scheduler keeps track of the process state of
each uid, and uses that to bump up the priority of jobs
associated with foreground uids.  Added constants for priorities
since we have different places specifying priorities.

Also cleaned up a bit of the reporting of "wrapped" jobs from
the sync manager -- there is a new tag argument that can be supplied,
to have the name and tag used in various places be based on that
instead of the useless internal class name.

Change-Id: I8781750ddfac1472a98e1873fc38c014425db3d6
diff --git a/core/java/android/app/JobSchedulerImpl.java b/core/java/android/app/JobSchedulerImpl.java
index dacf4ea..b3a486f 100644
--- a/core/java/android/app/JobSchedulerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -46,9 +46,9 @@
     }
 
     @Override
-    public int scheduleAsPackage(JobInfo job, String packageName, int userId) {
+    public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag) {
         try {
-            return mBinder.scheduleAsPackage(job, packageName, userId);
+            return mBinder.scheduleAsPackage(job, packageName, userId, tag);
         } catch (RemoteException e) {
             return JobScheduler.RESULT_FAILURE;
         }
diff --git a/core/java/android/app/job/IJobScheduler.aidl b/core/java/android/app/job/IJobScheduler.aidl
index f0c3302..3379f2e 100644
--- a/core/java/android/app/job/IJobScheduler.aidl
+++ b/core/java/android/app/job/IJobScheduler.aidl
@@ -24,7 +24,7 @@
   */
 interface IJobScheduler {
     int schedule(in JobInfo job);
-    int scheduleAsPackage(in JobInfo job, String packageName, int userId);
+    int scheduleAsPackage(in JobInfo job, String packageName, int userId, String tag);
     void cancel(int jobId);
     void cancelAll();
     List<JobInfo> getAllPendingJobs();
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 5398e7f..4cbaf6c 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -83,6 +83,31 @@
      */
     public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
 
+    /**
+     * Default of {@link #getPriority}.
+     * @hide
+     */
+    public static final int PRIORITY_DEFAULT = 0;
+
+    /**
+     * Value of {@link #getPriority} for expedited syncs.
+     * @hide
+     */
+    public static final int PRIORITY_SYNC_EXPEDITED = 10;
+
+    /**
+     * Value of {@link #getPriority} for first time initialization syncs.
+     * @hide
+     */
+    public static final int PRIORITY_SYNC_INITIALIZATION = 20;
+
+    /**
+     * Value of {@link #getPriority} for the current foreground app (overrides the supplied
+     * JobInfo priority if it is smaller).
+     * @hide
+     */
+    public static final int PRIORITY_FOREGROUND_APP = 30;
+
     private final int jobId;
     private final PersistableBundle extras;
     private final ComponentName service;
@@ -406,7 +431,7 @@
         private int mJobId;
         private PersistableBundle mExtras = PersistableBundle.EMPTY;
         private ComponentName mJobService;
-        private int mPriority;
+        private int mPriority = PRIORITY_DEFAULT;
         // Requirements.
         private boolean mRequiresCharging;
         private boolean mRequiresDeviceIdle;
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 5e1a4256..d1e563f 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -68,10 +68,11 @@
      * @param packageName The package on behalf of which the job is to be scheduled. This will be
      *                    used to track battery usage and appIdleState.
      * @param userId    User on behalf of whom this job is to be scheduled.
+     * @param tag Debugging tag for dumps associated with this job (instead of the service class)
      * @return {@link #RESULT_SUCCESS} or {@link #RESULT_FAILURE}
      * @hide
      */
-    public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId);
+    public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag);
 
     /**
      * Cancel a job that is pending in the JobScheduler.
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f7db1f7..95a9875 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1319,7 +1319,7 @@
         }
 
         getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
-                syncOperation.target.userId);
+                syncOperation.target.userId, "sync");
     }
 
     /**
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 957b087..804be4e 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -17,6 +17,7 @@
 package com.android.server.content;
 
 import android.accounts.Account;
+import android.app.job.JobInfo;
 import android.content.pm.PackageManager;
 import android.content.ContentResolver;
 import android.os.Bundle;
@@ -320,11 +321,11 @@
 
     int findPriority() {
         if (isInitialization()) {
-            return 2;
+            return JobInfo.PRIORITY_SYNC_INITIALIZATION;
         } else if (isExpedited()) {
-            return 1;
+            return JobInfo.PRIORITY_SYNC_EXPEDITED;
         }
-        return 0;
+        return JobInfo.PRIORITY_DEFAULT;
     }
 
     private String toKey() {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 42ecc06..b638dc5 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -52,6 +52,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import android.util.SparseBooleanArray;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.DeviceIdleController;
 import com.android.server.LocalServices;
@@ -159,11 +160,16 @@
     boolean mDeviceIdleMode;
 
     /**
-     * What we last reported to DeviceIdleController about wheter we are active.
+     * What we last reported to DeviceIdleController about whether we are active.
      */
     boolean mReportedActive;
 
     /**
+     * Which uids are currently in the foreground.
+     */
+    final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
+
+    /**
      * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
      * still clean up. On reinstall the package will have a new uid.
      */
@@ -199,9 +205,11 @@
 
     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
+            updateUidState(uid, procState);
         }
 
         @Override public void onUidGone(int uid) throws RemoteException {
+            updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         }
 
         @Override public void onUidActive(int uid) throws RemoteException {
@@ -236,11 +244,12 @@
      * @return Result of this operation. See <code>JobScheduler#RESULT_*</code> return codes.
      */
     public int schedule(JobInfo job, int uId) {
-        return scheduleAsPackage(job, uId, null, -1);
+        return scheduleAsPackage(job, uId, null, -1, null);
     }
 
-    public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
-        JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId);
+    public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId,
+            String tag) {
+        JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
         try {
             if (ActivityManagerNative.getDefault().getAppStartMode(uId,
                     job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
@@ -353,6 +362,25 @@
         }
     }
 
+    void updateUidState(int uid, int procState) {
+        synchronized (mLock) {
+            boolean foreground = procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+            boolean changed = false;
+            if (foreground) {
+                if (!mForegroundUids.get(uid)) {
+                    changed = true;
+                    mForegroundUids.put(uid, true);
+                }
+            } else {
+                int index = mForegroundUids.indexOfKey(uid);
+                if (index >= 0) {
+                    mForegroundUids.removeAt(index);
+                    changed = true;
+                }
+            }
+        }
+    }
+
     void updateIdleMode(boolean enabled) {
         boolean changed = false;
         boolean rocking;
@@ -462,7 +490,8 @@
             mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
             try {
                 ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
-                        ActivityManager.UID_OBSERVER_IDLE);
+                        ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
+                        | ActivityManager.UID_OBSERVER_IDLE);
             } catch (RemoteException e) {
                 // ignored; both services live in system_server
             }
@@ -948,6 +977,17 @@
         }
     }
 
+    private int evaluateJobPriorityLocked(JobStatus job) {
+        int priority = job.getPriority();
+        if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) {
+            return priority;
+        }
+        if (mForegroundUids.get(job.getSourceUid())) {
+            return JobInfo.PRIORITY_FOREGROUND_APP;
+        }
+        return priority;
+    }
+
     /**
      * Takes jobs from pending queue and runs them on available contexts.
      * If no contexts are available, preempts lower priority jobs to
@@ -984,6 +1024,8 @@
                 continue;
             }
 
+            nextPending.lastEvaluatedPriority = evaluateJobPriorityLocked(nextPending);
+
             // Find a context for nextPending. The context should be available OR
             // it should have lowest priority among all running jobs
             // (sharing the same Uid as nextPending)
@@ -1005,11 +1047,11 @@
                 if (job.getUid() != nextPending.getUid()) {
                     continue;
                 }
-                if (job.getPriority() >= nextPending.getPriority()) {
+                if (evaluateJobPriorityLocked(job) >= nextPending.lastEvaluatedPriority) {
                     continue;
                 }
-                if (minPriority > nextPending.getPriority()) {
-                    minPriority = nextPending.getPriority();
+                if (minPriority > nextPending.lastEvaluatedPriority) {
+                    minPriority = nextPending.lastEvaluatedPriority;
                     minPriorityContextId = i;
                 }
             }
@@ -1033,18 +1075,18 @@
                     mActiveServices.get(i).preemptExecutingJob();
                     preservePreferredUid = true;
                 } else {
+                    final JobStatus pendingJob = contextIdToJobMap[i];
                     if (DEBUG) {
                         Slog.d(TAG, "About to run job on context "
-                                + String.valueOf(i) + ", job: " + contextIdToJobMap[i]);
+                                + String.valueOf(i) + ", job: " + pendingJob);
                     }
                     for (int ic=0; ic<mControllers.size(); ic++) {
-                        StateController controller = mControllers.get(ic);
-                        controller.prepareForExecutionLocked(contextIdToJobMap[i]);
+                        mControllers.get(ic).prepareForExecutionLocked(pendingJob);
                     }
-                    if (!mActiveServices.get(i).executeRunnableJob(contextIdToJobMap[i])) {
-                        Slog.d(TAG, "Error executing " + contextIdToJobMap[i]);
+                    if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {
+                        Slog.d(TAG, "Error executing " + pendingJob);
                     }
-                    mPendingJobs.remove(contextIdToJobMap[i]);
+                    mPendingJobs.remove(pendingJob);
                 }
             }
             if (!preservePreferredUid) {
@@ -1143,7 +1185,7 @@
         }
 
         @Override
-        public int scheduleAsPackage(JobInfo job, String packageName, int userId)
+        public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag)
                 throws RemoteException {
             final int callerUid = Binder.getCallingUid();
             if (DEBUG) {
@@ -1165,7 +1207,7 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 return JobSchedulerService.this.scheduleAsPackage(job, callerUid,
-                        packageName, userId);
+                        packageName, userId, tag);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -1287,7 +1329,22 @@
                 mControllers.get(i).dumpControllerStateLocked(pw);
             }
             pw.println();
-            pw.println(printPendingQueue());
+            pw.println("Foreground uids:");
+            for (int i=0; i<mForegroundUids.size(); i++) {
+                pw.print("  "); pw.println(UserHandle.formatUid(mForegroundUids.keyAt(i)));
+            }
+            pw.println();
+            pw.println("Pending queue:");
+            for (int i=0; i<mPendingJobs.size(); i++) {
+                JobStatus job = mPendingJobs.get(i);
+                pw.print("  Pending #"); pw.print(i); pw.print(": ");
+                pw.println(job.toShortString());
+                int priority = evaluateJobPriorityLocked(job);
+                if (priority != JobInfo.PRIORITY_DEFAULT) {
+                    pw.print("    Evaluated priority: "); pw.println(priority);
+                }
+                pw.print("    Tag: "); pw.println(job.getTag());
+            }
             pw.println();
             pw.println("Active jobs:");
             for (int i=0; i<mActiveServices.size(); i++) {
@@ -1303,6 +1360,10 @@
                     pw.print(" fromnow=");
                     pw.println(timeout-now);
                     jsc.getRunningJob().dump(pw, "  ");
+                    int priority = evaluateJobPriorityLocked(jsc.getRunningJob());
+                    if (priority != JobInfo.PRIORITY_DEFAULT) {
+                        pw.print("  Evaluated priority: "); pw.println(priority);
+                    }
                 }
             }
             pw.println();
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 48549ce..7c5e336 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -204,7 +204,7 @@
                 return false;
             }
             try {
-                mBatteryStats.noteJobStart(job.getName(), job.getSourceUid());
+                mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
             } catch (RemoteException e) {
                 // Whatever.
             }
@@ -580,7 +580,8 @@
                 }
                 completedJob = mRunningJob;
                 try {
-                    mBatteryStats.noteJobFinish(mRunningJob.getName(), mRunningJob.getSourceUid());
+                    mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
+                            mRunningJob.getSourceUid());
                 } catch (RemoteException e) {
                     // Whatever.
                 }
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index f8753d6..4268dab 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -323,6 +323,9 @@
             if (jobStatus.getSourcePackageName() != null) {
                 out.attribute(null, "sourcePackageName", jobStatus.getSourcePackageName());
             }
+            if (jobStatus.getSourceTag() != null) {
+                out.attribute(null, "sourceTag", jobStatus.getSourceTag());
+            }
             out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId()));
             out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
             out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
@@ -542,6 +545,8 @@
 
             final String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
 
+            final String sourceTag = parser.getAttributeValue(null, "sourceTag");
+
             int eventType;
             // Read out constraints tag.
             do {
@@ -656,7 +661,7 @@
             parser.nextTag(); // Consume </extras>
 
             JobStatus js = new JobStatus(
-                    jobBuilder.build(), uid, sourcePackageName, sourceUserId,
+                    jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag,
                     elapsedRuntimes.first, elapsedRuntimes.second);
             return js;
         }
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index f835069..e6fbc39 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -58,12 +58,14 @@
     final JobInfo job;
     /** Uid of the package requesting this job. */
     final int callingUid;
-    final String name;
-    final String tag;
+    final String batteryName;
 
     final String sourcePackageName;
     final int sourceUserId;
     final int sourceUid;
+    final String sourceTag;
+
+    final String tag;
 
     /**
      * Earliest point in the future at which this job will be eligible to run. A value of 0
@@ -87,6 +89,8 @@
     public ArraySet<Uri> changedUris;
     public ArraySet<String> changedAuthorities;
 
+    public int lastEvaluatedPriority;
+
     /**
      * For use only by ContentObserverController: state it is maintaining about content URIs
      * being observed.
@@ -99,12 +103,10 @@
     }
 
     private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
-            int sourceUserId, int numFailures, long earliestRunTimeElapsedMillis,
+            int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
             long latestRunTimeElapsedMillis) {
         this.job = job;
         this.callingUid = callingUid;
-        this.name = job.getService().flattenToShortString();
-        this.tag = "*job*/" + this.name;
 
         int tempSourceUid = -1;
         if (sourceUserId != -1 && sourcePackageName != null) {
@@ -119,12 +121,25 @@
             this.sourceUid = callingUid;
             this.sourceUserId = UserHandle.getUserId(callingUid);
             this.sourcePackageName = job.getService().getPackageName();
+            this.sourceTag = null;
         } else {
             this.sourceUid = tempSourceUid;
             this.sourceUserId = sourceUserId;
             this.sourcePackageName = sourcePackageName;
+            this.sourceTag = tag;
         }
 
+        if (this.sourceTag != null) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(job.getService().getPackageName());
+            sb.append('/');
+            sb.append(this.sourceTag);
+            this.batteryName = sb.toString();
+        } else {
+            this.batteryName = job.getService().flattenToShortString();
+        }
+        this.tag = "*job*/" + this.batteryName;
+
         this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
         this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
         this.numFailures = numFailures;
@@ -158,8 +173,8 @@
     public JobStatus(JobStatus jobStatus) {
         this(jobStatus.getJob(), jobStatus.getUid(),
                 jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
-                jobStatus.getNumFailures(), jobStatus.getEarliestRunTime(),
-                jobStatus.getLatestRunTimeElapsed());
+                jobStatus.getSourceTag(), jobStatus.getNumFailures(),
+                jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
     }
 
     /**
@@ -169,18 +184,18 @@
      * 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 callingUid, String sourcePackageName,
-            int sourceUserId, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
-        this(job, callingUid, sourcePackageName, sourceUserId, 0, earliestRunTimeElapsedMillis,
-                latestRunTimeElapsedMillis);
+    public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
+            String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
+        this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
+                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
     }
 
     /** 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(),
-                rescheduling.getSourcePackageName(),
-                rescheduling.getSourceUserId(), backoffAttempt, newEarliestRuntimeElapsedMillis,
+                rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
+                rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
                 newLatestRuntimeElapsedMillis);
     }
 
@@ -192,7 +207,7 @@
      * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
      */
     public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
-            int sourceUserId) {
+            int sourceUserId, String tag) {
         final long elapsedNow = SystemClock.elapsedRealtime();
         final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
         if (job.isPeriodic()) {
@@ -204,7 +219,7 @@
             latestRunTimeElapsedMillis = job.hasLateConstraint() ?
                     elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
         }
-        return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, 0,
+        return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
     }
 
@@ -240,12 +255,16 @@
         return UserHandle.getUserId(callingUid);
     }
 
+    public String getSourceTag() {
+        return sourceTag;
+    }
+
     public int getUid() {
         return callingUid;
     }
 
-    public String getName() {
-        return name;
+    public String getBatteryName() {
+        return batteryName;
     }
 
     public String getTag() {
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index e64481e..edbff83 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -59,7 +59,7 @@
                 .setMinimumLatency(runFromMillis)
                 .setPersisted(true)
                 .build();
-        final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1);
+        final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(ts);
         Thread.sleep(IO_WAIT);
         // Manually load tasks from xml file.
@@ -92,8 +92,8 @@
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
                 .setPersisted(true)
                 .build();
-        final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1);
-        final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1);
+        final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1, null);
+        final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(taskStatus1);
         mTaskStoreUnderTest.add(taskStatus2);
         Thread.sleep(IO_WAIT);
@@ -141,7 +141,7 @@
         extras.putInt("into", 3);
         b.setExtras(extras);
         final JobInfo task = b.build();
-        JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1);
+        JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
 
         mTaskStoreUnderTest.add(taskStatus);
         Thread.sleep(IO_WAIT);
@@ -159,7 +159,7 @@
                 .setRequiresCharging(true)
                 .setPersisted(true);
         JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID,
-                "com.google.android.gms", 0);
+                "com.google.android.gms", 0, null);
 
         mTaskStoreUnderTest.add(taskStatus);
         Thread.sleep(IO_WAIT);
@@ -180,7 +180,7 @@
                 .setPeriodic(5*60*60*1000, 1*60*60*1000)
                 .setRequiresCharging(true)
                 .setPersisted(true);
-        JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
+        JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
 
         mTaskStoreUnderTest.add(taskStatus);
         Thread.sleep(IO_WAIT);
@@ -206,7 +206,7 @@
         final long invalidEarlyRuntimeElapsedMillis =
                 invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
         final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
-                0 /* sourceUserId */,
+                0 /* sourceUserId */, "someTag",
                 invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
 
         mTaskStoreUnderTest.add(js);
@@ -232,7 +232,7 @@
                 .setOverrideDeadline(5000)
                 .setPriority(42)
                 .setPersisted(true);
-        final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
+        final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(js);
         Thread.sleep(IO_WAIT);
         final JobSet jobStatusSet = new JobSet();
@@ -248,12 +248,12 @@
         JobInfo.Builder b = new Builder(42, mComponent)
                 .setOverrideDeadline(10000)
                 .setPersisted(false);
-        JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
+        JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(jsNonPersisted);
         b = new Builder(43, mComponent)
                 .setOverrideDeadline(10000)
                 .setPersisted(true);
-        JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
+        JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(jsPersisted);
         Thread.sleep(IO_WAIT);
         final JobSet jobStatusSet = new JobSet();