diff --git a/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl b/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl index 2bb82bd006def..f8dc3b01162c8 100644 --- a/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl @@ -32,6 +32,8 @@ oneway interface IJobService { /** Stop execution of application's job. */ @UnsupportedAppUsage void stopJob(in JobParameters jobParams); + /** Inform the job of a change in the network it should use. */ + void onNetworkChanged(in JobParameters jobParams); /** Update JS of how much data has been downloaded. */ void getTransferredDownloadBytes(in JobParameters jobParams, in JobWorkItem jobWorkItem); /** Update JS of how much data has been uploaded. */ diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java index 86e61832611e7..a7aae17c2ddd8 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java @@ -290,7 +290,8 @@ public class JobParameters implements Parcelable { private final boolean mIsUserInitiated; private final Uri[] mTriggeredContentUris; private final String[] mTriggeredContentAuthorities; - private final Network network; + @Nullable + private Network mNetwork; private int mStopReason = STOP_REASON_UNDEFINED; private int mInternalStopReason = INTERNAL_STOP_REASON_UNKNOWN; @@ -313,7 +314,7 @@ public class JobParameters implements Parcelable { this.mIsUserInitiated = isUserInitiated; this.mTriggeredContentUris = triggeredContentUris; this.mTriggeredContentAuthorities = triggeredContentAuthorities; - this.network = network; + this.mNetwork = network; this.mJobNamespace = namespace; } @@ -477,7 +478,7 @@ public class JobParameters implements Parcelable { * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest) */ public @Nullable Network getNetwork() { - return network; + return mNetwork; } /** @@ -572,15 +573,20 @@ public class JobParameters implements Parcelable { mTriggeredContentUris = in.createTypedArray(Uri.CREATOR); mTriggeredContentAuthorities = in.createStringArray(); if (in.readInt() != 0) { - network = Network.CREATOR.createFromParcel(in); + mNetwork = Network.CREATOR.createFromParcel(in); } else { - network = null; + mNetwork = null; } mStopReason = in.readInt(); mInternalStopReason = in.readInt(); debugStopReason = in.readString(); } + /** @hide */ + public void setNetwork(@Nullable Network network) { + mNetwork = network; + } + /** @hide */ public void setStopReason(@StopReason int reason, int internalStopReason, String debugStopReason) { @@ -613,9 +619,9 @@ public class JobParameters implements Parcelable { dest.writeBoolean(mIsUserInitiated); dest.writeTypedArray(mTriggeredContentUris, flags); dest.writeStringArray(mTriggeredContentAuthorities); - if (network != null) { + if (mNetwork != null) { dest.writeInt(1); - network.writeToParcel(dest, flags); + mNetwork.writeToParcel(dest, flags); } else { dest.writeInt(0); } diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java index 449c316c1c65c..31d2266feab48 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobService.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java @@ -27,6 +27,7 @@ import android.app.Service; import android.compat.Compatibility; import android.content.Intent; import android.os.IBinder; +import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -131,6 +132,11 @@ public abstract class JobService extends Service { return JobService.this.getTransferredUploadBytes(params, item); } } + + @Override + public void onNetworkChanged(@NonNull JobParameters params) { + JobService.this.onNetworkChanged(params); + } }; } return mEngine.getBinder(); @@ -231,6 +237,27 @@ public abstract class JobService extends Service { */ public abstract boolean onStopJob(JobParameters params); + /** + * This method is called that for a job that has a network constraint when the network + * to be used by the job changes. The new network object will be available via + * {@link JobParameters#getNetwork()}. Any network that results in this method call will + * match the job's requested network constraints. + * + *
+ * For example, if a device is on a metered mobile network and then connects to an
+ * unmetered WiFi network, and the job has indicated that both networks satisfy its
+ * network constraint, then this method will be called to notify the job of the new
+ * unmetered WiFi network.
+ *
+ * @param params The parameters identifying this job, similar to what was supplied to the job in
+ * the {@link #onStartJob(JobParameters)} callback, but with an updated network.
+ * @see JobInfo.Builder#setRequiredNetwork(android.net.NetworkRequest)
+ * @see JobInfo.Builder#setRequiredNetworkType(int)
+ */
+ public void onNetworkChanged(@NonNull JobParameters params) {
+ Log.w(TAG, "onNetworkChanged() not implemented. Must override in a subclass.");
+ }
+
/**
* Update the amount of data this job is estimated to transfer after the job has started.
*
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
index 697641ef65eb6..79d87edff9b2c 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
@@ -76,6 +76,8 @@ public abstract class JobServiceEngine {
private static final int MSG_UPDATE_ESTIMATED_NETWORK_BYTES = 6;
/** Message that the client wants to give JobScheduler a notification to tie to the job. */
private static final int MSG_SET_NOTIFICATION = 7;
+ /** Message that the network to use has changed. */
+ private static final int MSG_INFORM_OF_NETWORK_CHANGE = 8;
private final IJobService mBinder;
@@ -127,6 +129,16 @@ public abstract class JobServiceEngine {
}
}
+ @Override
+ public void onNetworkChanged(JobParameters jobParams) throws RemoteException {
+ JobServiceEngine service = mService.get();
+ if (service != null) {
+ service.mHandler.removeMessages(MSG_INFORM_OF_NETWORK_CHANGE);
+ service.mHandler.obtainMessage(MSG_INFORM_OF_NETWORK_CHANGE, jobParams)
+ .sendToTarget();
+ }
+ }
+
@Override
public void stopJob(JobParameters jobParams) throws RemoteException {
JobServiceEngine service = mService.get();
@@ -271,6 +283,16 @@ public abstract class JobServiceEngine {
args.recycle();
break;
}
+ case MSG_INFORM_OF_NETWORK_CHANGE: {
+ final JobParameters params = (JobParameters) msg.obj;
+ try {
+ JobServiceEngine.this.onNetworkChanged(params);
+ } catch (Exception e) {
+ Log.e(TAG, "Error while executing job: " + params.getJobId());
+ throw new RuntimeException(e);
+ }
+ break;
+ }
default:
Log.e(TAG, "Unrecognised message received.");
break;
@@ -385,6 +407,15 @@ public abstract class JobServiceEngine {
m.sendToTarget();
}
+ /**
+ * Engine's report that the network for the job has changed.
+ *
+ * @see JobService#onNetworkChanged(JobParameters)
+ */
+ public void onNetworkChanged(@NonNull JobParameters params) {
+ Log.w(TAG, "onNetworkChanged() not implemented. Must override in a subclass.");
+ }
+
/**
* Engine's request to get how much data has been downloaded.
*
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index e0e0b4bd62e2f..bf8984feb0a7e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -1179,6 +1179,25 @@ class JobConcurrencyManager {
assignJobsToContextsLocked();
}
+ @Nullable
+ @GuardedBy("mLock")
+ JobServiceContext getRunningJobServiceContextLocked(JobStatus job) {
+ if (!mRunningJobs.contains(job)) {
+ return null;
+ }
+
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus executing = jsc.getRunningJobLocked();
+ if (executing == job) {
+ return jsc;
+ }
+ }
+ Slog.wtf(TAG, "Couldn't find running job on a context");
+ mRunningJobs.remove(job);
+ return null;
+ }
+
@GuardedBy("mLock")
boolean stopJobOnServiceContextLocked(JobStatus job,
@JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 4e52ed3529814..671608f0b11a9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -61,6 +61,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
+import android.net.Network;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
@@ -1939,6 +1940,17 @@ public class JobSchedulerService extends com.android.server.SystemService
}
}
+ @Override
+ public void onNetworkChanged(JobStatus jobStatus, Network newNetwork) {
+ synchronized (mLock) {
+ final JobServiceContext jsc =
+ mConcurrencyManager.getRunningJobServiceContextLocked(jobStatus);
+ if (jsc != null) {
+ jsc.informOfNetworkChangeLocked(newNetwork);
+ }
+ }
+ }
+
@Override
public void onRestrictedBucketChanged(List