diff options
6 files changed, 519 insertions, 5 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/IJobCallback.aidl b/apex/jobscheduler/framework/java/android/app/job/IJobCallback.aidl index d281da037fde..a3390b75b8bf 100644 --- a/apex/jobscheduler/framework/java/android/app/job/IJobCallback.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/IJobCallback.aidl @@ -30,6 +30,25 @@ import android.app.job.JobWorkItem; */ interface IJobCallback { /** + * Immediate callback to the system after sending a data transfer download progress request + * signal; used to quickly detect ANR. + * + * @param jobId Unique integer used to identify this job. + * @param workId Unique integer used to identify a specific work item. + * @param transferredBytes How much data has been downloaded, in bytes. + */ + void acknowledgeGetTransferredDownloadBytesMessage(int jobId, int workId, + long transferredBytes); + /** + * Immediate callback to the system after sending a data transfer upload progress request + * signal; used to quickly detect ANR. + * + * @param jobId Unique integer used to identify this job. + * @param workId Unique integer used to identify a specific work item. + * @param transferredBytes How much data has been uploaded, in bytes. + */ + void acknowledgeGetTransferredUploadBytesMessage(int jobId, int workId, long transferredBytes); + /** * Immediate callback to the system after sending a start signal, used to quickly detect ANR. * * @param jobId Unique integer used to identify this job. @@ -65,4 +84,24 @@ interface IJobCallback { */ @UnsupportedAppUsage void jobFinished(int jobId, boolean reschedule); + /* + * Inform JobScheduler of a change in the estimated transfer payload. + * + * @param jobId Unique integer used to identify this job. + * @param item The particular JobWorkItem this progress is associated with, if any. + * @param downloadBytes How many bytes the app expects to download. + * @param uploadBytes How many bytes the app expects to upload. + */ + void updateEstimatedNetworkBytes(int jobId, in JobWorkItem item, + long downloadBytes, long uploadBytes); + /* + * Update JobScheduler of how much data the job has successfully transferred. + * + * @param jobId Unique integer used to identify this job. + * @param item The particular JobWorkItem this progress is associated with, if any. + * @param transferredDownloadBytes The number of bytes that have successfully been downloaded. + * @param transferredUploadBytes The number of bytes that have successfully been uploaded. + */ + void updateTransferredNetworkBytes(int jobId, in JobWorkItem item, + long transferredDownloadBytes, long transferredUploadBytes); } diff --git a/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl b/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl index 22ad252b9639..2bb82bd006de 100644 --- a/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl @@ -17,6 +17,7 @@ package android.app.job; import android.app.job.JobParameters; +import android.app.job.JobWorkItem; /** * Interface that the framework uses to communicate with application code that implements a @@ -31,4 +32,8 @@ oneway interface IJobService { /** Stop execution of application's job. */ @UnsupportedAppUsage void stopJob(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. */ + void getTransferredUploadBytes(in JobParameters jobParams, in JobWorkItem jobWorkItem); } diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java index e0db3a6464a8..76f71a2b9fe2 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java @@ -23,8 +23,11 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.UserIdInt; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.content.ClipData; import android.content.Context; +import android.os.Build; import android.os.Bundle; import android.os.PersistableBundle; @@ -94,6 +97,16 @@ import java.util.List; */ @SystemService(Context.JOB_SCHEDULER_SERVICE) public abstract class JobScheduler { + /** + * Whether to throw an exception when an app doesn't properly implement all the necessary + * data transfer APIs. + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION = 255371817L; + /** @hide */ @IntDef(prefix = { "RESULT_" }, value = { RESULT_FAILURE, diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java index d184d44239ed..bad641cf8bf6 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobService.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java @@ -16,7 +16,13 @@ package android.app.job; +import static android.app.job.JobScheduler.THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION; + +import android.annotation.BytesLong; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Service; +import android.compat.Compatibility; import android.content.Intent; import android.os.IBinder; @@ -72,6 +78,28 @@ public abstract class JobService extends Service { public boolean onStopJob(JobParameters params) { return JobService.this.onStopJob(params); } + + @Override + @BytesLong + public long getTransferredDownloadBytes(@NonNull JobParameters params, + @Nullable JobWorkItem item) { + if (item == null) { + return JobService.this.getTransferredDownloadBytes(); + } else { + return JobService.this.getTransferredDownloadBytes(item); + } + } + + @Override + @BytesLong + public long getTransferredUploadBytes(@NonNull JobParameters params, + @Nullable JobWorkItem item) { + if (item == null) { + return JobService.this.getTransferredUploadBytes(); + } else { + return JobService.this.getTransferredUploadBytes(item); + } + } }; } return mEngine.getBinder(); @@ -171,4 +199,169 @@ public abstract class JobService extends Service { * to end the job entirely. Regardless of the value returned, your job must stop executing. */ public abstract boolean onStopJob(JobParameters params); + + /** + * Update how much data this job will transfer. This method can + * be called multiple times within the first 30 seconds after + * {@link #onStartJob(JobParameters)} has been called. Only + * one call will be heeded after that time has passed. + * + * This method (or an overload) must be called within the first + * 30 seconds for a data transfer job if a payload size estimate + * was not provided at the time of scheduling. + * + * @hide + * @see JobInfo.Builder#setEstimatedNetworkBytes(long, long) + */ + public final void updateEstimatedNetworkBytes(@NonNull JobParameters params, + @BytesLong long downloadBytes, @BytesLong long uploadBytes) { + mEngine.updateEstimatedNetworkBytes(params, null, downloadBytes, uploadBytes); + } + + /** + * Update how much data will transfer for the JobWorkItem. This + * method can be called multiple times within the first 30 seconds + * after {@link #onStartJob(JobParameters)} has been called. + * Only one call will be heeded after that time has passed. + * + * This method (or an overload) must be called within the first + * 30 seconds for a data transfer job if a payload size estimate + * was not provided at the time of scheduling. + * + * @hide + * @see JobInfo.Builder#setEstimatedNetworkBytes(long, long) + */ + public final void updateEstimatedNetworkBytes(@NonNull JobParameters params, + @NonNull JobWorkItem jobWorkItem, + @BytesLong long downloadBytes, @BytesLong long uploadBytes) { + mEngine.updateEstimatedNetworkBytes(params, jobWorkItem, downloadBytes, uploadBytes); + } + + /** + * Tell JobScheduler how much data has successfully been transferred for the data transfer job. + * @hide + */ + public final void updateTransferredNetworkBytes(@NonNull JobParameters params, + @BytesLong long transferredDownloadBytes, @BytesLong long transferredUploadBytes) { + mEngine.updateTransferredNetworkBytes(params, null, + transferredDownloadBytes, transferredUploadBytes); + } + + /** + * Tell JobScheduler how much data has been transferred for the data transfer + * {@link JobWorkItem}. + * @hide + */ + public final void updateTransferredNetworkBytes(@NonNull JobParameters params, + @NonNull JobWorkItem item, + @BytesLong long transferredDownloadBytes, @BytesLong long transferredUploadBytes) { + mEngine.updateTransferredNetworkBytes(params, item, + transferredDownloadBytes, transferredUploadBytes); + } + + /** + * Get the number of bytes the app has successfully downloaded for this job. JobScheduler + * will call this if the job has specified positive estimated download bytes and + * {@link #updateTransferredNetworkBytes(JobParameters, long, long)} + * hasn't been called recently. + * + * <p> + * This must be implemented for all data transfer jobs. + * + * @hide + * @see JobInfo.Builder#setEstimatedNetworkBytes(long, long) + * @see JobInfo#NETWORK_BYTES_UNKNOWN + */ + // TODO(255371817): specify the actual time JS will wait for progress before requesting + @BytesLong + public long getTransferredDownloadBytes() { + if (Compatibility.isChangeEnabled(THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION)) { + // Regular jobs don't have to implement this and JobScheduler won't call this API for + // non-data transfer jobs. + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + return 0; + } + + /** + * Get the number of bytes the app has successfully downloaded for this job. JobScheduler + * will call this if the job has specified positive estimated upload bytes and + * {@link #updateTransferredNetworkBytes(JobParameters, long, long)} + * hasn't been called recently. + * + * <p> + * This must be implemented for all data transfer jobs. + * + * @hide + * @see JobInfo.Builder#setEstimatedNetworkBytes(long, long) + * @see JobInfo#NETWORK_BYTES_UNKNOWN + */ + // TODO(255371817): specify the actual time JS will wait for progress before requesting + @BytesLong + public long getTransferredUploadBytes() { + if (Compatibility.isChangeEnabled(THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION)) { + // Regular jobs don't have to implement this and JobScheduler won't call this API for + // non-data transfer jobs. + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + return 0; + } + + /** + * Get the number of bytes the app has successfully downloaded for this job. JobScheduler + * will call this if the job has specified positive estimated download bytes and + * {@link #updateTransferredNetworkBytes(JobParameters, JobWorkItem, long, long)} + * hasn't been called recently and the job has + * {@link JobWorkItem JobWorkItems} that have been + * {@link JobParameters#dequeueWork dequeued} but not + * {@link JobParameters#completeWork(JobWorkItem) completed}. + * + * <p> + * This must be implemented for all data transfer jobs. + * + * @hide + * @see JobInfo#NETWORK_BYTES_UNKNOWN + */ + // TODO(255371817): specify the actual time JS will wait for progress before requesting + @BytesLong + public long getTransferredDownloadBytes(@NonNull JobWorkItem item) { + if (item == null) { + return getTransferredDownloadBytes(); + } + if (Compatibility.isChangeEnabled(THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION)) { + // Regular jobs don't have to implement this and JobScheduler won't call this API for + // non-data transfer jobs. + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + return 0; + } + + /** + * Get the number of bytes the app has successfully downloaded for this job. JobScheduler + * will call this if the job has specified positive estimated upload bytes and + * {@link #updateTransferredNetworkBytes(JobParameters, JobWorkItem, long, long)} + * hasn't been called recently and the job has + * {@link JobWorkItem JobWorkItems} that have been + * {@link JobParameters#dequeueWork dequeued} but not + * {@link JobParameters#completeWork(JobWorkItem) completed}. + * + * <p> + * This must be implemented for all data transfer jobs. + * + * @hide + * @see JobInfo#NETWORK_BYTES_UNKNOWN + */ + // TODO(255371817): specify the actual time JS will wait for progress before requesting + @BytesLong + public long getTransferredUploadBytes(@NonNull JobWorkItem item) { + if (item == null) { + return getTransferredUploadBytes(); + } + if (Compatibility.isChangeEnabled(THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION)) { + // Regular jobs don't have to implement this and JobScheduler won't call this API for + // non-data transfer jobs. + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + return 0; + } } diff --git a/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java index 3d43d20e7955..83296a63205a 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java @@ -16,7 +16,13 @@ package android.app.job; +import static android.app.job.JobScheduler.THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION; + +import android.annotation.BytesLong; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Service; +import android.compat.Compatibility; import android.content.Intent; import android.os.Handler; import android.os.IBinder; @@ -25,6 +31,8 @@ import android.os.Message; import android.os.RemoteException; import android.util.Log; +import com.android.internal.os.SomeArgs; + import java.lang.ref.WeakReference; /** @@ -51,6 +59,20 @@ public abstract class JobServiceEngine { * Message that the client has completed execution of this job. */ private static final int MSG_JOB_FINISHED = 2; + /** + * Message that will result in a call to + * {@link #getTransferredDownloadBytes(JobParameters, JobWorkItem)}. + */ + private static final int MSG_GET_TRANSFERRED_DOWNLOAD_BYTES = 3; + /** + * Message that will result in a call to + * {@link #getTransferredUploadBytes(JobParameters, JobWorkItem)}. + */ + private static final int MSG_GET_TRANSFERRED_UPLOAD_BYTES = 4; + /** Message that the client wants to update JobScheduler of the data transfer progress. */ + private static final int MSG_UPDATE_TRANSFERRED_NETWORK_BYTES = 5; + /** Message that the client wants to update JobScheduler of the estimated transfer size. */ + private static final int MSG_UPDATE_ESTIMATED_NETWORK_BYTES = 6; private final IJobService mBinder; @@ -68,6 +90,32 @@ public abstract class JobServiceEngine { } @Override + public void getTransferredDownloadBytes(@NonNull JobParameters jobParams, + @Nullable JobWorkItem jobWorkItem) throws RemoteException { + JobServiceEngine service = mService.get(); + if (service != null) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = jobParams; + args.arg2 = jobWorkItem; + service.mHandler.obtainMessage(MSG_GET_TRANSFERRED_DOWNLOAD_BYTES, args) + .sendToTarget(); + } + } + + @Override + public void getTransferredUploadBytes(@NonNull JobParameters jobParams, + @Nullable JobWorkItem jobWorkItem) throws RemoteException { + JobServiceEngine service = mService.get(); + if (service != null) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = jobParams; + args.arg2 = jobWorkItem; + service.mHandler.obtainMessage(MSG_GET_TRANSFERRED_UPLOAD_BYTES, args) + .sendToTarget(); + } + } + + @Override public void startJob(JobParameters jobParams) throws RemoteException { JobServiceEngine service = mService.get(); if (service != null) { @@ -98,9 +146,9 @@ public abstract class JobServiceEngine { @Override public void handleMessage(Message msg) { - final JobParameters params = (JobParameters) msg.obj; switch (msg.what) { - case MSG_EXECUTE_JOB: + case MSG_EXECUTE_JOB: { + final JobParameters params = (JobParameters) msg.obj; try { boolean workOngoing = JobServiceEngine.this.onStartJob(params); ackStartMessage(params, workOngoing); @@ -109,7 +157,9 @@ public abstract class JobServiceEngine { throw new RuntimeException(e); } break; - case MSG_STOP_JOB: + } + case MSG_STOP_JOB: { + final JobParameters params = (JobParameters) msg.obj; try { boolean ret = JobServiceEngine.this.onStopJob(params); ackStopMessage(params, ret); @@ -118,7 +168,9 @@ public abstract class JobServiceEngine { throw new RuntimeException(e); } break; - case MSG_JOB_FINISHED: + } + case MSG_JOB_FINISHED: { + final JobParameters params = (JobParameters) msg.obj; final boolean needsReschedule = (msg.arg2 == 1); IJobCallback callback = params.getCallback(); if (callback != null) { @@ -132,19 +184,117 @@ public abstract class JobServiceEngine { Log.e(TAG, "finishJob() called for a nonexistent job id."); } break; + } + case MSG_GET_TRANSFERRED_DOWNLOAD_BYTES: { + final SomeArgs args = (SomeArgs) msg.obj; + final JobParameters params = (JobParameters) args.arg1; + final JobWorkItem item = (JobWorkItem) args.arg2; + try { + long ret = JobServiceEngine.this.getTransferredDownloadBytes(params, item); + ackGetTransferredDownloadBytesMessage(params, item, ret); + } catch (Exception e) { + Log.e(TAG, "Application unable to handle getTransferredDownloadBytes.", e); + throw new RuntimeException(e); + } + args.recycle(); + break; + } + case MSG_GET_TRANSFERRED_UPLOAD_BYTES: { + final SomeArgs args = (SomeArgs) msg.obj; + final JobParameters params = (JobParameters) args.arg1; + final JobWorkItem item = (JobWorkItem) args.arg2; + try { + long ret = JobServiceEngine.this.getTransferredUploadBytes(params, item); + ackGetTransferredUploadBytesMessage(params, item, ret); + } catch (Exception e) { + Log.e(TAG, "Application unable to handle getTransferredUploadBytes.", e); + throw new RuntimeException(e); + } + args.recycle(); + break; + } + case MSG_UPDATE_TRANSFERRED_NETWORK_BYTES: { + final SomeArgs args = (SomeArgs) msg.obj; + final JobParameters params = (JobParameters) args.arg1; + IJobCallback callback = params.getCallback(); + if (callback != null) { + try { + callback.updateTransferredNetworkBytes(params.getJobId(), + (JobWorkItem) args.arg2, args.argl1, args.argl2); + } catch (RemoteException e) { + Log.e(TAG, "Error updating data transfer progress to system:" + + " binder has gone away."); + } + } else { + Log.e(TAG, "updateDataTransferProgress() called for a nonexistent job id."); + } + args.recycle(); + break; + } + case MSG_UPDATE_ESTIMATED_NETWORK_BYTES: { + final SomeArgs args = (SomeArgs) msg.obj; + final JobParameters params = (JobParameters) args.arg1; + IJobCallback callback = params.getCallback(); + if (callback != null) { + try { + callback.updateEstimatedNetworkBytes(params.getJobId(), + (JobWorkItem) args.arg2, args.argl1, args.argl2); + } catch (RemoteException e) { + Log.e(TAG, "Error updating estimated transfer size to system:" + + " binder has gone away."); + } + } else { + Log.e(TAG, + "updateEstimatedNetworkBytes() called for a nonexistent job id."); + } + args.recycle(); + break; + } default: Log.e(TAG, "Unrecognised message received."); break; } } + private void ackGetTransferredDownloadBytesMessage(@NonNull JobParameters params, + @Nullable JobWorkItem item, long progress) { + final IJobCallback callback = params.getCallback(); + final int jobId = params.getJobId(); + final int workId = item == null ? -1 : item.getWorkId(); + if (callback != null) { + try { + callback.acknowledgeGetTransferredDownloadBytesMessage(jobId, workId, progress); + } catch (RemoteException e) { + Log.e(TAG, "System unreachable for returning progress."); + } + } else if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Attempting to ack a job that has already been processed."); + } + } + + private void ackGetTransferredUploadBytesMessage(@NonNull JobParameters params, + @Nullable JobWorkItem item, long progress) { + final IJobCallback callback = params.getCallback(); + final int jobId = params.getJobId(); + final int workId = item == null ? -1 : item.getWorkId(); + if (callback != null) { + try { + callback.acknowledgeGetTransferredUploadBytesMessage(jobId, workId, progress); + } catch (RemoteException e) { + Log.e(TAG, "System unreachable for returning progress."); + } + } else if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Attempting to ack a job that has already been processed."); + } + } + private void ackStartMessage(JobParameters params, boolean workOngoing) { final IJobCallback callback = params.getCallback(); final int jobId = params.getJobId(); if (callback != null) { try { callback.acknowledgeStartMessage(jobId, workOngoing); - } catch(RemoteException e) { + } catch (RemoteException e) { Log.e(TAG, "System unreachable for starting job."); } } else { @@ -213,4 +363,73 @@ public abstract class JobServiceEngine { m.arg2 = needsReschedule ? 1 : 0; m.sendToTarget(); } + + /** + * Engine's request to get how much data has been downloaded. + * + * @hide + * @see JobService#getTransferredDownloadBytes() + */ + @BytesLong + public long getTransferredDownloadBytes(@NonNull JobParameters params, + @Nullable JobWorkItem item) { + if (Compatibility.isChangeEnabled(THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION)) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + return 0; + } + + /** + * Engine's request to get how much data has been uploaded. + * + * @hide + * @see JobService#getTransferredUploadBytes() + */ + @BytesLong + public long getTransferredUploadBytes(@NonNull JobParameters params, + @Nullable JobWorkItem item) { + if (Compatibility.isChangeEnabled(THROW_ON_INVALID_DATA_TRANSFER_IMPLEMENTATION)) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + return 0; + } + + /** + * Call in to engine to report data transfer progress. + * + * @hide + * @see JobService#updateTransferredNetworkBytes(JobParameters, long, long) + */ + public void updateTransferredNetworkBytes(@NonNull JobParameters params, + @Nullable JobWorkItem item, long downloadBytes, long uploadBytes) { + if (params == null) { + throw new NullPointerException("params"); + } + SomeArgs args = SomeArgs.obtain(); + args.arg1 = params; + args.arg2 = item; + args.argl1 = downloadBytes; + args.argl2 = uploadBytes; + mHandler.obtainMessage(MSG_UPDATE_TRANSFERRED_NETWORK_BYTES, args).sendToTarget(); + } + + /** + * Call in to engine to report data transfer progress. + * + * @hide + * @see JobService#updateEstimatedNetworkBytes(JobParameters, JobWorkItem, long, long) + */ + public void updateEstimatedNetworkBytes(@NonNull JobParameters params, + @NonNull JobWorkItem item, + @BytesLong long downloadBytes, @BytesLong long uploadBytes) { + if (params == null) { + throw new NullPointerException("params"); + } + SomeArgs args = SomeArgs.obtain(); + args.arg1 = params; + args.arg2 = item; + args.argl1 = downloadBytes; + args.argl2 = uploadBytes; + mHandler.obtainMessage(MSG_UPDATE_ESTIMATED_NETWORK_BYTES, args).sendToTarget(); + } }
\ No newline at end of file diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 334647ef8331..9aa6b1c298ef 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -21,6 +21,7 @@ import static android.app.job.JobInfo.getPriorityString; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import android.annotation.BytesLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.job.IJobCallback; @@ -187,6 +188,18 @@ public final class JobServiceContext implements ServiceConnection { public long mStoppedTime; @Override + public void acknowledgeGetTransferredDownloadBytesMessage(int jobId, int workId, + @BytesLong long transferredBytes) { + doAcknowledgeGetTransferredDownloadBytesMessage(this, jobId, workId, transferredBytes); + } + + @Override + public void acknowledgeGetTransferredUploadBytesMessage(int jobId, int workId, + @BytesLong long transferredBytes) { + doAcknowledgeGetTransferredUploadBytesMessage(this, jobId, workId, transferredBytes); + } + + @Override public void acknowledgeStartMessage(int jobId, boolean ongoing) { doAcknowledgeStartMessage(this, jobId, ongoing); } @@ -210,6 +223,18 @@ public final class JobServiceContext implements ServiceConnection { public void jobFinished(int jobId, boolean reschedule) { doJobFinished(this, jobId, reschedule); } + + @Override + public void updateEstimatedNetworkBytes(int jobId, JobWorkItem item, + long downloadBytes, long uploadBytes) { + doUpdateEstimatedNetworkBytes(this, jobId, item, downloadBytes, uploadBytes); + } + + @Override + public void updateTransferredNetworkBytes(int jobId, JobWorkItem item, + long downloadBytes, long uploadBytes) { + doUpdateTransferredNetworkBytes(this, jobId, item, downloadBytes, uploadBytes); + } } JobServiceContext(JobSchedulerService service, JobConcurrencyManager concurrencyManager, @@ -506,6 +531,16 @@ public final class JobServiceContext implements ServiceConnection { } } + private void doAcknowledgeGetTransferredDownloadBytesMessage(JobCallback jobCallback, int jobId, + int workId, @BytesLong long transferredBytes) { + // TODO(255393346): Make sure apps call this appropriately and monitor for abuse + } + + private void doAcknowledgeGetTransferredUploadBytesMessage(JobCallback jobCallback, int jobId, + int workId, @BytesLong long transferredBytes) { + // TODO(255393346): Make sure apps call this appropriately and monitor for abuse + } + void doAcknowledgeStopMessage(JobCallback cb, int jobId, boolean reschedule) { doCallback(cb, reschedule, null); } @@ -558,6 +593,16 @@ public final class JobServiceContext implements ServiceConnection { } } + private void doUpdateTransferredNetworkBytes(JobCallback jobCallback, int jobId, + @Nullable JobWorkItem item, long downloadBytes, long uploadBytes) { + // TODO(255393346): Make sure apps call this appropriately and monitor for abuse + } + + private void doUpdateEstimatedNetworkBytes(JobCallback jobCallback, int jobId, + @Nullable JobWorkItem item, long downloadBytes, long uploadBytes) { + // TODO(255393346): Make sure apps call this appropriately and monitor for abuse + } + /** * We acquire/release a wakelock on onServiceConnected/unbindService. This mirrors the work * we intend to send to the client - we stop sending work when the service is unbound so until |