Merge "Add data transfer JobService APIs."

This commit is contained in:
Kweku Adams
2022-11-11 19:34:24 +00:00
committed by Android (Google) Code Review
7 changed files with 519 additions and 5 deletions

View File

@@ -29,6 +29,25 @@ import android.app.job.JobWorkItem;
* {@hide}
*/
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.
*
@@ -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);
}

View File

@@ -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);
}

View File

@@ -22,8 +22,11 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
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;
@@ -93,6 +96,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,

View File

@@ -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,161 @@ 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.
*
* @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.
*
* @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.
*/
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}.
*/
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.
*
* @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.
*
* @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.
*
* @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.
*
* @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;
}
}

View File

@@ -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;
@@ -67,6 +89,32 @@ public abstract class JobServiceEngine {
mService = new WeakReference<>(service);
}
@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();
@@ -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,69 @@ public abstract class JobServiceEngine {
m.arg2 = needsReschedule ? 1 : 0;
m.sendToTarget();
}
/**
* Engine's request to get how much data has been downloaded.
*
* @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.
*
* @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.
*
* @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.
*
* @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();
}
}

View File

@@ -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;
@@ -186,6 +187,18 @@ public final class JobServiceContext implements ServiceConnection {
public String mStoppedReason;
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,
@@ -497,6 +522,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);
}
@@ -549,6 +584,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

View File

@@ -8448,19 +8448,31 @@ package android.app.job {
public abstract class JobService extends android.app.Service {
ctor public JobService();
method public long getTransferredDownloadBytes();
method public long getTransferredDownloadBytes(@NonNull android.app.job.JobWorkItem);
method public long getTransferredUploadBytes();
method public long getTransferredUploadBytes(@NonNull android.app.job.JobWorkItem);
method public final void jobFinished(android.app.job.JobParameters, boolean);
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract boolean onStartJob(android.app.job.JobParameters);
method public abstract boolean onStopJob(android.app.job.JobParameters);
method public final void updateEstimatedNetworkBytes(@NonNull android.app.job.JobParameters, long, long);
method public final void updateEstimatedNetworkBytes(@NonNull android.app.job.JobParameters, @NonNull android.app.job.JobWorkItem, long, long);
method public final void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, long, long);
method public final void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, @NonNull android.app.job.JobWorkItem, long, long);
field public static final String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
}
public abstract class JobServiceEngine {
ctor public JobServiceEngine(android.app.Service);
method public final android.os.IBinder getBinder();
method public long getTransferredDownloadBytes(@NonNull android.app.job.JobParameters, @Nullable android.app.job.JobWorkItem);
method public long getTransferredUploadBytes(@NonNull android.app.job.JobParameters, @Nullable android.app.job.JobWorkItem);
method public void jobFinished(android.app.job.JobParameters, boolean);
method public abstract boolean onStartJob(android.app.job.JobParameters);
method public abstract boolean onStopJob(android.app.job.JobParameters);
method public void updateEstimatedNetworkBytes(@NonNull android.app.job.JobParameters, @NonNull android.app.job.JobWorkItem, long, long);
method public void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, @Nullable android.app.job.JobWorkItem, long, long);
}
public final class JobWorkItem implements android.os.Parcelable {