From 60977f42dbbcf6edfd9b18fdd08af54006860d90 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 13 Apr 2017 13:48:46 -0700 Subject: [PATCH] Introduce NETWORK_TYPE_METERED job constraint When your job wants non-WiFi connectivity. Bug 37219369 Test: CTS Change-Id: I0981938061b6b7f354e7236221552ef03976f470 --- api/current.txt | 1 + api/system-current.txt | 1 + api/test-current.txt | 1 + core/java/android/app/job/JobInfo.java | 11 ++-- .../server/job/JobSchedulerService.java | 3 +- .../java/com/android/server/job/JobStore.java | 13 +++-- .../controllers/ConnectivityController.java | 16 +++--- .../server/job/controllers/JobStatus.java | 51 +++++++++++++++---- 8 files changed, 72 insertions(+), 25 deletions(-) diff --git a/api/current.txt b/api/current.txt index 6e30fd876ca29..15b251b167c3f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6791,6 +6791,7 @@ package android.app.job { field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 + field public static final int NETWORK_TYPE_METERED = 4; // 0x4 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index b0eb10db5d8a2..e1c58ae751f1d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -7222,6 +7222,7 @@ package android.app.job { field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 + field public static final int NETWORK_TYPE_METERED = 4; // 0x4 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 diff --git a/api/test-current.txt b/api/test-current.txt index 52a07faabeed0..7d006a99bf382 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6821,6 +6821,7 @@ package android.app.job { field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 + field public static final int NETWORK_TYPE_METERED = 4; // 0x4 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index 412e4459ecddc..23baa17d947f8 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -51,6 +51,8 @@ public class JobInfo implements Parcelable { public static final int NETWORK_TYPE_UNMETERED = 2; /** This job requires network connectivity that is not roaming. */ public static final int NETWORK_TYPE_NOT_ROAMING = 3; + /** This job requires metered connectivity such as most cellular data networks. */ + public static final int NETWORK_TYPE_METERED = 4; /** * Amount of backoff a job has initially by default, in milliseconds. @@ -347,10 +349,13 @@ public class JobInfo implements Parcelable { } /** - * One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY}, + * The kind of connectivity requirements that the job has. + * + * @return One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY}, * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, - * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}, or - * {@link android.app.job.JobInfo#NETWORK_TYPE_NOT_ROAMING}. + * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}, + * {@link android.app.job.JobInfo#NETWORK_TYPE_METERED}, or + * {@link android.app.job.JobInfo#NETWORK_TYPE_NOT_ROAMING}, */ public int getNetworkType() { return networkType; diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index a0d0d777637ff..d01de3c9157d8 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -1271,8 +1271,7 @@ public final class JobSchedulerService extends com.android.server.SystemService if (job.hasIdleConstraint()) { idleCount++; } - if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint() - || job.hasNotRoamingConstraint()) { + if (job.hasConnectivityConstraint()) { connectivityCount++; } if (job.hasChargingConstraint()) { diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index fcc0827908928..2e6cd3febd2d6 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -368,13 +368,16 @@ public class JobStore { */ private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException { out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS); - if (jobStatus.hasConnectivityConstraint()) { + if (jobStatus.needsAnyConnectivity()) { out.attribute(null, "connectivity", Boolean.toString(true)); } - if (jobStatus.hasUnmeteredConstraint()) { + if (jobStatus.needsMeteredConnectivity()) { + out.attribute(null, "metered", Boolean.toString(true)); + } + if (jobStatus.needsUnmeteredConnectivity()) { out.attribute(null, "unmetered", Boolean.toString(true)); } - if (jobStatus.hasNotRoamingConstraint()) { + if (jobStatus.needsNonRoamingConnectivity()) { out.attribute(null, "not-roaming", Boolean.toString(true)); } if (jobStatus.hasIdleConstraint()) { @@ -713,6 +716,10 @@ public class JobStore { if (val != null) { jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); } + val = parser.getAttributeValue(null, "metered"); + if (val != null) { + jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED); + } val = parser.getAttributeValue(null, "unmetered"); if (val != null) { jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index b458d8b72adef..5ebcc93cda09e 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -84,8 +84,7 @@ public class ConnectivityController extends StateController implements @Override public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { - if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint() - || jobStatus.hasNotRoamingConstraint()) { + if (jobStatus.hasConnectivityConstraint()) { updateConstraintsSatisfied(jobStatus, null); mTrackedJobs.add(jobStatus); } @@ -94,8 +93,7 @@ public class ConnectivityController extends StateController implements @Override public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) { - if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint() - || jobStatus.hasNotRoamingConstraint()) { + if (jobStatus.hasConnectivityConstraint()) { mTrackedJobs.remove(jobStatus); } } @@ -114,11 +112,13 @@ public class ConnectivityController extends StateController implements && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); final boolean connected = info != null && info.isConnected(); final boolean connectionUsable = connected && validated; + final boolean metered = connected && info.isMetered(); final boolean unmetered = connected && !info.isMetered(); final boolean notRoaming = connected && !info.isRoaming(); boolean changed = false; changed |= jobStatus.setConnectivityConstraintSatisfied(connectionUsable); + changed |= jobStatus.setMeteredConstraintSatisfied(metered); changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered); changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming); @@ -134,6 +134,7 @@ public class ConnectivityController extends StateController implements + " for " + jobStatus + ": usable=" + connectionUsable + " connected=" + connected + " validated=" + validated + + " metered=" + metered + " unmetered=" + unmetered + " notRoaming=" + notRoaming); } @@ -244,9 +245,10 @@ public class ConnectivityController extends StateController implements js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); - pw.print(": C="); pw.print(js.hasConnectivityConstraint()); - pw.print(": UM="); pw.print(js.hasUnmeteredConstraint()); - pw.print(": NR="); pw.println(js.hasNotRoamingConstraint()); + pw.print(": C="); pw.print(js.needsAnyConnectivity()); + pw.print(": M="); pw.print(js.needsMeteredConnectivity()); + pw.print(": UM="); pw.print(js.needsUnmeteredConnectivity()); + pw.print(": NR="); pw.println(js.needsNonRoamingConnectivity()); } } } 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 4cdce5f52f8f7..e8cc078b7eb1a 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -68,6 +68,11 @@ public final class JobStatus { static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26; static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25; static final int CONSTRAINT_NOT_ROAMING = 1<<24; + static final int CONSTRAINT_METERED = 1<<23; + + static final int CONNECTIVITY_MASK = + CONSTRAINT_UNMETERED | CONSTRAINT_CONNECTIVITY | + CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED; // Soft override: ignore constraints like time that don't affect API availability public static final int OVERRIDE_SOFT = 1; @@ -191,15 +196,28 @@ public final class JobStatus { this.numFailures = numFailures; int requiredConstraints = job.getConstraintFlags(); - if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) { - requiredConstraints |= CONSTRAINT_CONNECTIVITY; - } - if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) { - requiredConstraints |= CONSTRAINT_UNMETERED; - } - if (job.getNetworkType() == JobInfo.NETWORK_TYPE_NOT_ROAMING) { - requiredConstraints |= CONSTRAINT_NOT_ROAMING; + + switch (job.getNetworkType()) { + case JobInfo.NETWORK_TYPE_NONE: + // No constraint. + break; + case JobInfo.NETWORK_TYPE_ANY: + requiredConstraints |= CONSTRAINT_CONNECTIVITY; + break; + case JobInfo.NETWORK_TYPE_UNMETERED: + requiredConstraints |= CONSTRAINT_UNMETERED; + break; + case JobInfo.NETWORK_TYPE_NOT_ROAMING: + requiredConstraints |= CONSTRAINT_NOT_ROAMING; + break; + case JobInfo.NETWORK_TYPE_METERED: + requiredConstraints |= CONSTRAINT_METERED; + break; + default: + Slog.w(TAG, "Unrecognized networking constraint " + job.getNetworkType()); + break; } + if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) { requiredConstraints |= CONSTRAINT_TIMING_DELAY; } @@ -467,15 +485,24 @@ public final class JobStatus { return job.getFlags(); } + /** Does this job have any sort of networking constraint? */ public boolean hasConnectivityConstraint() { + return (requiredConstraints&CONNECTIVITY_MASK) != 0; + } + + public boolean needsAnyConnectivity() { return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0; } - public boolean hasUnmeteredConstraint() { + public boolean needsUnmeteredConnectivity() { return (requiredConstraints&CONSTRAINT_UNMETERED) != 0; } - public boolean hasNotRoamingConstraint() { + public boolean needsMeteredConnectivity() { + return (requiredConstraints&CONSTRAINT_METERED) != 0; + } + + public boolean needsNonRoamingConnectivity() { return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0; } @@ -571,6 +598,10 @@ public final class JobStatus { return setConstraintSatisfied(CONSTRAINT_UNMETERED, state); } + boolean setMeteredConstraintSatisfied(boolean state) { + return setConstraintSatisfied(CONSTRAINT_METERED, state); + } + boolean setNotRoamingConstraintSatisfied(boolean state) { return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state); }