API changes for DownloadManager and JobScheduler.

To support moving DownloadManager, add new JobScheduler network type
constraint that matches "any network except roaming."  Also add an
API to get a specific JobInfo by ID.

Since the default network can be different on a per-app basis, and
individual apps may be blocked due to app standby, evaluate job
connectivity constraints on a per-UID basis.  To implement this
cleanly, add NetworkInfo.isMetered() to match the isRoaming() API.

Add new DownloadManager APIs to support charging and device idle
constraints, which are plumbed through to JobScheduler under the
hood when scheduled.

Add filtering to JobScheduler dumpsys to omit noisy details for
packages the caller isn't interested in.

Bug: 28098882, 26571724, 19821935
Change-Id: I09ca7184ef7ce6adba399f579d415a5fb2ea6110
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 7df8ffd..075a88f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -40,6 +40,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
@@ -336,6 +337,19 @@
         }
     }
 
+    public JobInfo getPendingJob(int uid, int jobId) {
+        synchronized (mLock) {
+            List<JobStatus> jobs = mJobs.getJobsByUid(uid);
+            for (int i = jobs.size() - 1; i >= 0; i--) {
+                JobStatus job = jobs.get(i);
+                if (job.getJobId() == jobId) {
+                    return job.getJob();
+                }
+            }
+            return null;
+        }
+    }
+
     void cancelJobsForUser(int userHandle) {
         List<JobStatus> jobsForUser;
         synchronized (mLock) {
@@ -912,7 +926,8 @@
                     if (job.hasIdleConstraint()) {
                         idleCount++;
                     }
-                    if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
+                    if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()
+                            || job.hasNotRoamingConstraint()) {
                         connectivityCount++;
                     }
                     if (job.hasChargingConstraint()) {
@@ -1346,6 +1361,18 @@
         }
 
         @Override
+        public JobInfo getPendingJob(int jobId) throws RemoteException {
+            final int uid = Binder.getCallingUid();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return JobSchedulerService.this.getPendingJob(uid, jobId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
         public void cancelAll() throws RemoteException {
             final int uid = Binder.getCallingUid();
 
@@ -1378,7 +1405,7 @@
 
             long identityToken = Binder.clearCallingIdentity();
             try {
-                JobSchedulerService.this.dumpInternal(pw);
+                JobSchedulerService.this.dumpInternal(pw, args);
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
             }
@@ -1450,7 +1477,17 @@
         return s.toString();
     }
 
-    void dumpInternal(final PrintWriter pw) {
+    void dumpInternal(final PrintWriter pw, String[] args) {
+        int filterUid = -1;
+        if (!ArrayUtils.isEmpty(args)) {
+            try {
+                filterUid = getContext().getPackageManager().getPackageUid(args[0],
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES);
+            } catch (NameNotFoundException ignored) {
+            }
+        }
+
+        final int filterUidFinal = filterUid;
         final long now = SystemClock.elapsedRealtime();
         synchronized (mLock) {
             pw.println("Started users: " + Arrays.toString(mStartedUsers));
@@ -1463,6 +1500,13 @@
                     public void process(JobStatus job) {
                         pw.print("  Job #"); pw.print(index++); pw.print(": ");
                         pw.println(job.toShortString());
+
+                        // Skip printing details if the caller requested a filter
+                        if (filterUidFinal != -1 && job.getUid() != filterUidFinal
+                                && job.getSourceUid() != filterUidFinal) {
+                            return;
+                        }
+
                         job.dump(pw, "    ", true);
                         pw.print("    Ready: ");
                         pw.print(mHandler.isReadyToBeExecutedLocked(job));