summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt5
-rw-r--r--api/system-current.txt5
-rw-r--r--api/test-current.txt5
-rw-r--r--core/java/android/app/job/JobInfo.java67
-rw-r--r--core/java/android/app/job/JobWorkItem.java35
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java2
-rw-r--r--services/core/java/com/android/server/job/controllers/ConnectivityController.java57
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java43
8 files changed, 215 insertions, 4 deletions
diff --git a/api/current.txt b/api/current.txt
index bdfa68ef6615..2fd75c7c5975 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6834,6 +6834,7 @@ package android.app.job {
method public int getBackoffPolicy();
method public android.content.ClipData getClipData();
method public int getClipGrantFlags();
+ method public long getEstimatedNetworkBytes();
method public android.os.PersistableBundle getExtras();
method public long getFlexMillis();
method public int getId();
@@ -6861,6 +6862,7 @@ package android.app.job {
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
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_BYTES_UNKNOWN = -1; // 0xffffffff
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
@@ -6874,6 +6876,7 @@ package android.app.job {
method public android.app.job.JobInfo build();
method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
method public android.app.job.JobInfo.Builder setClipData(android.content.ClipData, int);
+ method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
method public android.app.job.JobInfo.Builder setMinimumLatency(long);
method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
@@ -6948,8 +6951,10 @@ package android.app.job {
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
+ ctor public JobWorkItem(android.content.Intent, long);
method public int describeContents();
method public int getDeliveryCount();
+ method public long getEstimatedNetworkBytes();
method public android.content.Intent getIntent();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
diff --git a/api/system-current.txt b/api/system-current.txt
index e3162e3f0881..cf92177ded0b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7276,6 +7276,7 @@ package android.app.job {
method public int getBackoffPolicy();
method public android.content.ClipData getClipData();
method public int getClipGrantFlags();
+ method public long getEstimatedNetworkBytes();
method public android.os.PersistableBundle getExtras();
method public long getFlexMillis();
method public int getId();
@@ -7303,6 +7304,7 @@ package android.app.job {
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
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_BYTES_UNKNOWN = -1; // 0xffffffff
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
@@ -7316,6 +7318,7 @@ package android.app.job {
method public android.app.job.JobInfo build();
method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
method public android.app.job.JobInfo.Builder setClipData(android.content.ClipData, int);
+ method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
method public android.app.job.JobInfo.Builder setMinimumLatency(long);
method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
@@ -7391,8 +7394,10 @@ package android.app.job {
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
+ ctor public JobWorkItem(android.content.Intent, long);
method public int describeContents();
method public int getDeliveryCount();
+ method public long getEstimatedNetworkBytes();
method public android.content.Intent getIntent();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
diff --git a/api/test-current.txt b/api/test-current.txt
index a62399afd51c..ae7f4d665004 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6905,6 +6905,7 @@ package android.app.job {
method public int getBackoffPolicy();
method public android.content.ClipData getClipData();
method public int getClipGrantFlags();
+ method public long getEstimatedNetworkBytes();
method public android.os.PersistableBundle getExtras();
method public long getFlexMillis();
method public int getId();
@@ -6932,6 +6933,7 @@ package android.app.job {
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
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_BYTES_UNKNOWN = -1; // 0xffffffff
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
@@ -6945,6 +6947,7 @@ package android.app.job {
method public android.app.job.JobInfo build();
method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
method public android.app.job.JobInfo.Builder setClipData(android.content.ClipData, int);
+ method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
method public android.app.job.JobInfo.Builder setMinimumLatency(long);
method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
@@ -7019,8 +7022,10 @@ package android.app.job {
public final class JobWorkItem implements android.os.Parcelable {
ctor public JobWorkItem(android.content.Intent);
+ ctor public JobWorkItem(android.content.Intent, long);
method public int describeContents();
method public int getDeliveryCount();
+ method public long getEstimatedNetworkBytes();
method public android.content.Intent getIntent();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 1cde73a0af61..b640bd5bee2a 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -18,6 +18,7 @@ package android.app.job;
import static android.util.TimeUtils.formatDuration;
+import android.annotation.BytesLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -71,6 +72,9 @@ public class JobInfo implements Parcelable {
/** This job requires metered connectivity such as most cellular data networks. */
public static final int NETWORK_TYPE_METERED = 4;
+ /** Sentinel value indicating that bytes are unknown. */
+ public static final int NETWORK_BYTES_UNKNOWN = -1;
+
/**
* Amount of backoff a job has initially by default, in milliseconds.
*/
@@ -250,6 +254,7 @@ public class JobInfo implements Parcelable {
private final boolean hasEarlyConstraint;
private final boolean hasLateConstraint;
private final int networkType;
+ private final long networkBytes;
private final long minLatencyMillis;
private final long maxExecutionDelayMillis;
private final boolean isPeriodic;
@@ -387,6 +392,18 @@ public class JobInfo implements Parcelable {
}
/**
+ * Return the estimated size of network traffic that will be performed by
+ * this job, in bytes.
+ *
+ * @return Estimated size of network traffic, or
+ * {@link #NETWORK_BYTES_UNKNOWN} when unknown.
+ * @see Builder#setEstimatedNetworkBytes(long)
+ */
+ public @BytesLong long getEstimatedNetworkBytes() {
+ return networkBytes;
+ }
+
+ /**
* Set for a job that does not recur periodically, to specify a delay after which the job
* will be eligible for execution. This value is not set if the job recurs periodically.
*/
@@ -524,6 +541,9 @@ public class JobInfo implements Parcelable {
if (networkType != j.networkType) {
return false;
}
+ if (networkBytes != j.networkBytes) {
+ return false;
+ }
if (minLatencyMillis != j.minLatencyMillis) {
return false;
}
@@ -582,6 +602,7 @@ public class JobInfo implements Parcelable {
hashCode = 31 * hashCode + Boolean.hashCode(hasEarlyConstraint);
hashCode = 31 * hashCode + Boolean.hashCode(hasLateConstraint);
hashCode = 31 * hashCode + networkType;
+ hashCode = 31 * hashCode + Long.hashCode(networkBytes);
hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic);
@@ -612,6 +633,7 @@ public class JobInfo implements Parcelable {
triggerContentUpdateDelay = in.readLong();
triggerContentMaxDelay = in.readLong();
networkType = in.readInt();
+ networkBytes = in.readLong();
minLatencyMillis = in.readLong();
maxExecutionDelayMillis = in.readLong();
isPeriodic = in.readInt() == 1;
@@ -640,6 +662,7 @@ public class JobInfo implements Parcelable {
triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
triggerContentMaxDelay = b.mTriggerContentMaxDelay;
networkType = b.mNetworkType;
+ networkBytes = b.mNetworkBytes;
minLatencyMillis = b.mMinLatencyMillis;
maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
isPeriodic = b.mIsPeriodic;
@@ -677,6 +700,7 @@ public class JobInfo implements Parcelable {
out.writeLong(triggerContentUpdateDelay);
out.writeLong(triggerContentMaxDelay);
out.writeInt(networkType);
+ out.writeLong(networkBytes);
out.writeLong(minLatencyMillis);
out.writeLong(maxExecutionDelayMillis);
out.writeInt(isPeriodic ? 1 : 0);
@@ -810,6 +834,7 @@ public class JobInfo implements Parcelable {
// Requirements.
private int mConstraintFlags;
private int mNetworkType;
+ private long mNetworkBytes = NETWORK_BYTES_UNKNOWN;
private ArrayList<TriggerContentUri> mTriggerContentUris;
private long mTriggerContentUpdateDelay = -1;
private long mTriggerContentMaxDelay = -1;
@@ -931,6 +956,43 @@ public class JobInfo implements Parcelable {
}
/**
+ * Set the estimated size of network traffic that will be performed by
+ * this job, in bytes.
+ * <p>
+ * Apps are encouraged to provide values that are as accurate as
+ * possible, but when the exact size isn't available, an
+ * order-of-magnitude estimate can be provided instead. Here are some
+ * specific examples:
+ * <ul>
+ * <li>A job that is backing up a photo knows the exact size of that
+ * photo, so it should provide that size as the estimate.
+ * <li>A job that refreshes top news stories wouldn't know an exact
+ * size, but if the size is expected to be consistently around 100KB, it
+ * can provide that order-of-magnitude value as the estimate.
+ * <li>A job that synchronizes email could end up using an extreme range
+ * of data, from under 1KB when nothing has changed, to dozens of MB
+ * when there are new emails with attachments. Jobs that cannot provide
+ * reasonable estimates should leave this estimated value undefined.
+ * </ul>
+ * Note that the system may choose to delay jobs with large network
+ * usage estimates when the device has a poor network connection, in
+ * order to save battery.
+ *
+ * @param networkBytes The estimated size of network traffic that will
+ * be performed by this job, in bytes. This value only
+ * reflects the traffic that will be performed by the base
+ * job; if you're using {@link JobWorkItem} then you also
+ * need to define the network traffic used by each work item
+ * when constructing them.
+ * @see JobInfo#getEstimatedNetworkBytes()
+ * @see JobWorkItem#JobWorkItem(android.content.Intent, long)
+ */
+ public Builder setEstimatedNetworkBytes(@BytesLong long networkBytes) {
+ mNetworkBytes = networkBytes;
+ return this;
+ }
+
+ /**
* Specify that to run this job, the device must be charging (or be a
* non-battery-powered device connected to permanent power, such as Android TV
* devices). This defaults to {@code false}.
@@ -1156,6 +1218,11 @@ public class JobInfo implements Parcelable {
throw new IllegalArgumentException("You're trying to build a job with no " +
"constraints, this is not allowed.");
}
+ // Check that network estimates require network type
+ if (mNetworkBytes > 0 && mNetworkType == NETWORK_TYPE_NONE) {
+ throw new IllegalArgumentException(
+ "Can't provide estimated network usage without requiring a network");
+ }
// Check that a deadline was not set on a periodic job.
if (mIsPeriodic) {
if (mMaxExecutionDelayMillis != 0L) {
diff --git a/core/java/android/app/job/JobWorkItem.java b/core/java/android/app/job/JobWorkItem.java
index 0eb0450e8f2a..1c46e8ecbe52 100644
--- a/core/java/android/app/job/JobWorkItem.java
+++ b/core/java/android/app/job/JobWorkItem.java
@@ -16,6 +16,7 @@
package android.app.job;
+import android.annotation.BytesLong;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,6 +28,7 @@ import android.os.Parcelable;
*/
final public class JobWorkItem implements Parcelable {
final Intent mIntent;
+ final long mNetworkBytes;
int mDeliveryCount;
int mWorkId;
Object mGrants;
@@ -39,6 +41,22 @@ final public class JobWorkItem implements Parcelable {
*/
public JobWorkItem(Intent intent) {
mIntent = intent;
+ mNetworkBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
+ }
+
+ /**
+ * Create a new piece of work, which can be submitted to
+ * {@link JobScheduler#enqueue JobScheduler.enqueue}.
+ *
+ * @param intent The general Intent describing this work.
+ * @param networkBytes The estimated size of network traffic that will be
+ * performed by this job work item, in bytes. See
+ * {@link JobInfo.Builder#setEstimatedNetworkBytes(long)} for
+ * details about how to estimate.
+ */
+ public JobWorkItem(Intent intent, @BytesLong long networkBytes) {
+ mIntent = intent;
+ mNetworkBytes = networkBytes;
}
/**
@@ -49,6 +67,17 @@ final public class JobWorkItem implements Parcelable {
}
/**
+ * Return the estimated size of network traffic that will be performed by
+ * this job work item, in bytes.
+ *
+ * @return estimated size, or {@link JobInfo#NETWORK_BYTES_UNKNOWN} when
+ * unknown.
+ */
+ public @BytesLong long getEstimatedNetworkBytes() {
+ return mNetworkBytes;
+ }
+
+ /**
* Return the count of the number of times this work item has been delivered
* to the job. The value will be > 1 if it has been redelivered because the job
* was stopped or crashed while it had previously been delivered but before the
@@ -99,6 +128,10 @@ final public class JobWorkItem implements Parcelable {
sb.append(mWorkId);
sb.append(" intent=");
sb.append(mIntent);
+ if (mNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ sb.append(" networkBytes=");
+ sb.append(mNetworkBytes);
+ }
if (mDeliveryCount != 0) {
sb.append(" dcount=");
sb.append(mDeliveryCount);
@@ -118,6 +151,7 @@ final public class JobWorkItem implements Parcelable {
} else {
out.writeInt(0);
}
+ out.writeLong(mNetworkBytes);
out.writeInt(mDeliveryCount);
out.writeInt(mWorkId);
}
@@ -139,6 +173,7 @@ final public class JobWorkItem implements Parcelable {
} else {
mIntent = null;
}
+ mNetworkBytes = in.readLong();
mDeliveryCount = in.readInt();
mWorkId = in.readInt();
}
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index ae01c433fc8d..a7e674b5a3a1 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -65,7 +65,7 @@ public final class JobServiceContext implements ServiceConnection {
private static final boolean DEBUG = JobSchedulerService.DEBUG;
private static final String TAG = "JobServiceContext";
/** Amount of time a job is allowed to execute for before being considered timed-out. */
- private static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000; // 10mins.
+ public static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000; // 10mins.
/** Amount of time the JobScheduler waits for the initial service launch+bind. */
private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000;
/** Amount of time the JobScheduler will wait for a response from an app for a message. */
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 c928c07be983..ddee345a1c42 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -25,13 +25,16 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkPolicyManager;
+import android.net.TrafficStats;
import android.os.Process;
import android.os.UserHandle;
+import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobServiceContext;
import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
@@ -99,18 +102,66 @@ public final class ConnectivityController extends StateController implements
}
}
+ /**
+ * Test to see if running the given job on the given network is sane.
+ * <p>
+ * For example, if a job is trying to send 10MB over a 128Kbps EDGE
+ * connection, it would take 10.4 minutes, and has no chance of succeeding
+ * before the job times out, so we'd be insane to try running it.
+ */
+ private boolean isSane(JobStatus jobStatus, NetworkCapabilities capabilities) {
+ final long estimatedBytes = jobStatus.getEstimatedNetworkBytes();
+ if (estimatedBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
+ // We don't know how large the job is; cross our fingers!
+ return true;
+ }
+ if (capabilities == null) {
+ // We don't know what the network is like; cross our fingers!
+ return true;
+ }
+
+ // We don't ask developers to differentiate between upstream/downstream
+ // in their size estimates, so test against the slowest link direction.
+ final long downstream = capabilities.getLinkDownstreamBandwidthKbps();
+ final long upstream = capabilities.getLinkUpstreamBandwidthKbps();
+ final long slowest;
+ if (downstream > 0 && upstream > 0) {
+ slowest = Math.min(downstream, upstream);
+ } else if (downstream > 0) {
+ slowest = downstream;
+ } else if (upstream > 0) {
+ slowest = upstream;
+ } else {
+ // We don't know what the network is like; cross our fingers!
+ return true;
+ }
+
+ final long estimatedMillis = ((estimatedBytes * DateUtils.SECOND_IN_MILLIS)
+ / (slowest * TrafficStats.KB_IN_BYTES / 8));
+ if (estimatedMillis > JobServiceContext.EXECUTING_TIMESLICE_MILLIS) {
+ // If we'd never finish before the timeout, we'd be insane!
+ Slog.w(TAG, "Estimated " + estimatedBytes + " bytes over " + slowest
+ + " kbps network would take " + estimatedMillis + "ms; that's insane!");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
final int jobUid = jobStatus.getSourceUid();
final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
- final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobUid, ignoreBlocked);
final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked);
+ final NetworkInfo info = mConnManager.getNetworkInfoForUid(network, jobUid, ignoreBlocked);
+
final NetworkCapabilities capabilities = (network != null)
? mConnManager.getNetworkCapabilities(network) : null;
+ final boolean connected = (info != null) && info.isConnected();
final boolean validated = (capabilities != null)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
- final boolean connected = (info != null) && info.isConnected();
- final boolean connectionUsable = connected && validated;
+ final boolean sane = isSane(jobStatus, capabilities);
+ final boolean connectionUsable = connected && validated && sane;
final boolean metered = connected && (capabilities != null)
&& !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
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 1a27c0afb5ea..46ed84e599e8 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -219,6 +219,8 @@ public final class JobStatus {
*/
ContentObserverController.JobInstance contentObserverJobInstance;
+ private long totalNetworkBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
+
/** Provide a handle to the service that this job will be run on. */
public int getServiceToken() {
return callingUid;
@@ -296,6 +298,8 @@ public final class JobStatus {
mLastSuccessfulRunTime = lastSuccessfulRunTime;
mLastFailedRunTime = lastFailedRunTime;
+
+ updateEstimatedNetworkBytesLocked();
}
/** Copy constructor: used specifically when cloning JobStatus objects for persistence,
@@ -389,6 +393,7 @@ public final class JobStatus {
sourcePackageName, sourceUserId, toShortString()));
}
pendingWork.add(work);
+ updateEstimatedNetworkBytesLocked();
}
public JobWorkItem dequeueWorkLocked() {
@@ -401,6 +406,7 @@ public final class JobStatus {
executingWork.add(work);
work.bumpDeliveryCount();
}
+ updateEstimatedNetworkBytesLocked();
return work;
}
return null;
@@ -459,6 +465,7 @@ public final class JobStatus {
pendingWork = null;
executingWork = null;
incomingJob.nextPendingWorkId = nextPendingWorkId;
+ incomingJob.updateEstimatedNetworkBytesLocked();
} else {
// We are completely stopping the job... need to clean up work.
ungrantWorkList(am, pendingWork);
@@ -466,6 +473,7 @@ public final class JobStatus {
ungrantWorkList(am, executingWork);
executingWork = null;
}
+ updateEstimatedNetworkBytesLocked();
}
public void prepareLocked(IActivityManager am) {
@@ -568,6 +576,38 @@ public final class JobStatus {
return job.getFlags();
}
+ private void updateEstimatedNetworkBytesLocked() {
+ totalNetworkBytes = computeEstimatedNetworkBytesLocked();
+ }
+
+ private long computeEstimatedNetworkBytesLocked() {
+ // If any component of the job has unknown usage, we don't have a
+ // complete picture of what data will be used, and we have to treat the
+ // entire job as unknown.
+ long totalNetworkBytes = 0;
+ long networkBytes = job.getEstimatedNetworkBytes();
+ if (networkBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
+ return JobInfo.NETWORK_BYTES_UNKNOWN;
+ } else {
+ totalNetworkBytes += networkBytes;
+ }
+ if (pendingWork != null) {
+ for (int i = 0; i < pendingWork.size(); i++) {
+ networkBytes = pendingWork.get(i).getEstimatedNetworkBytes();
+ if (networkBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
+ return JobInfo.NETWORK_BYTES_UNKNOWN;
+ } else {
+ totalNetworkBytes += networkBytes;
+ }
+ }
+ }
+ return totalNetworkBytes;
+ }
+
+ public long getEstimatedNetworkBytes() {
+ return totalNetworkBytes;
+ }
+
/** Does this job have any sort of networking constraint? */
public boolean hasConnectivityConstraint() {
return (requiredConstraints&CONNECTIVITY_MASK) != 0;
@@ -1047,6 +1087,9 @@ public final class JobStatus {
if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
}
+ if (totalNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ pw.print(prefix); pw.print(" Network bytes: "); pw.println(totalNetworkBytes);
+ }
if (job.getMinLatencyMillis() != 0) {
pw.print(prefix); pw.print(" Minimum latency: ");
TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);