Merge "Introduce framework-minus-apex and create jobscheduler-framework.jar"

This commit is contained in:
Makoto Onuki
2019-08-12 18:49:51 +00:00
committed by Android (Google) Code Review
22 changed files with 85 additions and 33 deletions

View File

@@ -1,121 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// in android.app so ContextImpl has package access
package android.app;
import android.app.job.IJobScheduler;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.app.job.JobSnapshot;
import android.app.job.JobWorkItem;
import android.os.RemoteException;
import java.util.List;
// APEX NOTE: Class path referred to by robolectric, so can't move it.
/**
* Concrete implementation of the JobScheduler interface
* @hide
*/
public class JobSchedulerImpl extends JobScheduler {
IJobScheduler mBinder;
public JobSchedulerImpl(IJobScheduler binder) {
mBinder = binder;
}
@Override
public int schedule(JobInfo job) {
try {
return mBinder.schedule(job);
} catch (RemoteException e) {
return JobScheduler.RESULT_FAILURE;
}
}
@Override
public int enqueue(JobInfo job, JobWorkItem work) {
try {
return mBinder.enqueue(job, work);
} catch (RemoteException e) {
return JobScheduler.RESULT_FAILURE;
}
}
@Override
public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag) {
try {
return mBinder.scheduleAsPackage(job, packageName, userId, tag);
} catch (RemoteException e) {
return JobScheduler.RESULT_FAILURE;
}
}
@Override
public void cancel(int jobId) {
try {
mBinder.cancel(jobId);
} catch (RemoteException e) {}
}
@Override
public void cancelAll() {
try {
mBinder.cancelAll();
} catch (RemoteException e) {}
}
@Override
public List<JobInfo> getAllPendingJobs() {
try {
return mBinder.getAllPendingJobs().getList();
} catch (RemoteException e) {
return null;
}
}
@Override
public JobInfo getPendingJob(int jobId) {
try {
return mBinder.getPendingJob(jobId);
} catch (RemoteException e) {
return null;
}
}
@Override
public List<JobInfo> getStartedJobs() {
try {
return mBinder.getStartedJobs();
} catch (RemoteException e) {
return null;
}
}
@Override
public List<JobSnapshot> getAllJobSnapshots() {
try {
return mBinder.getAllJobSnapshots().getList();
} catch (RemoteException e) {
return null;
}
}
}

View File

@@ -1,68 +0,0 @@
/**
* Copyright 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
import android.app.job.JobWorkItem;
/**
* The server side of the JobScheduler IPC protocols. The app-side implementation
* invokes on this interface to indicate completion of the (asynchronous) instructions
* issued by the server.
*
* In all cases, the 'who' parameter is the caller's service binder, used to track
* which Job Service instance is reporting.
*
* {@hide}
*/
interface IJobCallback {
/**
* Immediate callback to the system after sending a start signal, used to quickly detect ANR.
*
* @param jobId Unique integer used to identify this job.
* @param ongoing True to indicate that the client is processing the job. False if the job is
* complete
*/
@UnsupportedAppUsage
void acknowledgeStartMessage(int jobId, boolean ongoing);
/**
* Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
*
* @param jobId Unique integer used to identify this job.
* @param reschedule Whether or not to reschedule this job.
*/
@UnsupportedAppUsage
void acknowledgeStopMessage(int jobId, boolean reschedule);
/*
* Called to deqeue next work item for the job.
*/
@UnsupportedAppUsage
JobWorkItem dequeueWork(int jobId);
/*
* Called to report that job has completed processing a work item.
*/
@UnsupportedAppUsage
boolean completeWork(int jobId, int workId);
/*
* Tell the job manager that the client is done with its execution, so that it can go on to
* the next one and stop attributing wakelock time to us etc.
*
* @param jobId Unique integer used to identify this job.
* @param reschedule Whether or not to reschedule this job.
*/
@UnsupportedAppUsage
void jobFinished(int jobId, boolean reschedule);
}

View File

@@ -1,38 +0,0 @@
/**
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
import android.app.job.JobInfo;
import android.app.job.JobSnapshot;
import android.app.job.JobWorkItem;
import android.content.pm.ParceledListSlice;
/**
* IPC interface that supports the app-facing {@link #JobScheduler} api.
* {@hide}
*/
interface IJobScheduler {
int schedule(in JobInfo job);
int enqueue(in JobInfo job, in JobWorkItem work);
int scheduleAsPackage(in JobInfo job, String packageName, int userId, String tag);
void cancel(int jobId);
void cancelAll();
ParceledListSlice getAllPendingJobs();
JobInfo getPendingJob(int jobId);
List<JobInfo> getStartedJobs();
ParceledListSlice getAllJobSnapshots();
}

View File

@@ -1,34 +0,0 @@
/**
* Copyright 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
import android.app.job.JobParameters;
/**
* Interface that the framework uses to communicate with application code that implements a
* JobService. End user code does not implement this interface directly; instead, the app's
* service implementation will extend android.app.job.JobService.
* {@hide}
*/
oneway interface IJobService {
/** Begin execution of application's job. */
@UnsupportedAppUsage
void startJob(in JobParameters jobParams);
/** Stop execution of application's job. */
@UnsupportedAppUsage
void stopJob(in JobParameters jobParams);
}

View File

@@ -1,19 +0,0 @@
/**
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
parcelable JobInfo;

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +0,0 @@
/**
* Copyright 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
parcelable JobParameters;

View File

@@ -1,372 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.app.job;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.app.job.IJobCallback;
import android.content.ClipData;
import android.net.Network;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteException;
/**
* Contains the parameters used to configure/identify your job. You do not create this object
* yourself, instead it is handed in to your application by the System.
*/
public class JobParameters implements Parcelable {
/** @hide */
public static final int REASON_CANCELED = JobProtoEnums.STOP_REASON_CANCELLED; // 0.
/** @hide */
public static final int REASON_CONSTRAINTS_NOT_SATISFIED =
JobProtoEnums.STOP_REASON_CONSTRAINTS_NOT_SATISFIED; //1.
/** @hide */
public static final int REASON_PREEMPT = JobProtoEnums.STOP_REASON_PREEMPT; // 2.
/** @hide */
public static final int REASON_TIMEOUT = JobProtoEnums.STOP_REASON_TIMEOUT; // 3.
/** @hide */
public static final int REASON_DEVICE_IDLE = JobProtoEnums.STOP_REASON_DEVICE_IDLE; // 4.
/** @hide */
public static final int REASON_DEVICE_THERMAL = JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5.
/**
* All the stop reason codes. This should be regarded as an immutable array at runtime.
* @hide
*/
public static final int[] JOB_STOP_REASON_CODES = {
REASON_CANCELED,
REASON_CONSTRAINTS_NOT_SATISFIED,
REASON_PREEMPT,
REASON_TIMEOUT,
REASON_DEVICE_IDLE,
REASON_DEVICE_THERMAL,
};
/** @hide */
public static String getReasonName(int reason) {
switch (reason) {
case REASON_CANCELED: return "canceled";
case REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints";
case REASON_PREEMPT: return "preempt";
case REASON_TIMEOUT: return "timeout";
case REASON_DEVICE_IDLE: return "device_idle";
case REASON_DEVICE_THERMAL: return "thermal";
default: return "unknown:" + reason;
}
}
@UnsupportedAppUsage
private final int jobId;
private final PersistableBundle extras;
private final Bundle transientExtras;
private final ClipData clipData;
private final int clipGrantFlags;
@UnsupportedAppUsage
private final IBinder callback;
private final boolean overrideDeadlineExpired;
private final Uri[] mTriggeredContentUris;
private final String[] mTriggeredContentAuthorities;
private final Network network;
private int stopReason; // Default value of stopReason is REASON_CANCELED
private String debugStopReason; // Human readable stop reason for debugging.
/** @hide */
public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
Bundle transientExtras, ClipData clipData, int clipGrantFlags,
boolean overrideDeadlineExpired, Uri[] triggeredContentUris,
String[] triggeredContentAuthorities, Network network) {
this.jobId = jobId;
this.extras = extras;
this.transientExtras = transientExtras;
this.clipData = clipData;
this.clipGrantFlags = clipGrantFlags;
this.callback = callback;
this.overrideDeadlineExpired = overrideDeadlineExpired;
this.mTriggeredContentUris = triggeredContentUris;
this.mTriggeredContentAuthorities = triggeredContentAuthorities;
this.network = network;
}
/**
* @return The unique id of this job, specified at creation time.
*/
public int getJobId() {
return jobId;
}
/**
* Reason onStopJob() was called on this job.
* @hide
*/
public int getStopReason() {
return stopReason;
}
/**
* Reason onStopJob() was called on this job.
* @hide
*/
public String getDebugStopReason() {
return debugStopReason;
}
/**
* @return The extras you passed in when constructing this job with
* {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will
* never be null. If you did not set any extras this will be an empty bundle.
*/
public @NonNull PersistableBundle getExtras() {
return extras;
}
/**
* @return The transient extras you passed in when constructing this job with
* {@link android.app.job.JobInfo.Builder#setTransientExtras(android.os.Bundle)}. This will
* never be null. If you did not set any extras this will be an empty bundle.
*/
public @NonNull Bundle getTransientExtras() {
return transientExtras;
}
/**
* @return The clip you passed in when constructing this job with
* {@link android.app.job.JobInfo.Builder#setClipData(ClipData, int)}. Will be null
* if it was not set.
*/
public @Nullable ClipData getClipData() {
return clipData;
}
/**
* @return The clip grant flags you passed in when constructing this job with
* {@link android.app.job.JobInfo.Builder#setClipData(ClipData, int)}. Will be 0
* if it was not set.
*/
public int getClipGrantFlags() {
return clipGrantFlags;
}
/**
* For jobs with {@link android.app.job.JobInfo.Builder#setOverrideDeadline(long)} set, this
* provides an easy way to tell whether the job is being executed due to the deadline
* expiring. Note: If the job is running because its deadline expired, it implies that its
* constraints will not be met.
*/
public boolean isOverrideDeadlineExpired() {
return overrideDeadlineExpired;
}
/**
* For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this
* reports which URIs have triggered the job. This will be null if either no URIs have
* triggered it (it went off due to a deadline or other reason), or the number of changed
* URIs is too large to report. Whether or not the number of URIs is too large, you can
* always use {@link #getTriggeredContentAuthorities()} to determine whether the job was
* triggered due to any content changes and the authorities they are associated with.
*/
public @Nullable Uri[] getTriggeredContentUris() {
return mTriggeredContentUris;
}
/**
* For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this
* reports which content authorities have triggered the job. It will only be null if no
* authorities have triggered it -- that is, the job executed for some other reason, such
* as a deadline expiring. If this is non-null, you can use {@link #getTriggeredContentUris()}
* to retrieve the details of which URIs changed (as long as that has not exceeded the maximum
* number it can reported).
*/
public @Nullable String[] getTriggeredContentAuthorities() {
return mTriggeredContentAuthorities;
}
/**
* Return the network that should be used to perform any network requests
* for this job.
* <p>
* Devices may have multiple active network connections simultaneously, or
* they may not have a default network route at all. To correctly handle all
* situations like this, your job should always use the network returned by
* this method instead of implicitly using the default network route.
* <p>
* Note that the system may relax the constraints you originally requested,
* such as allowing a {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over
* a metered network when there is a surplus of metered data available.
*
* @return the network that should be used to perform any network requests
* for this job, or {@code null} if this job didn't set any required
* network type.
* @see JobInfo.Builder#setRequiredNetworkType(int)
*/
public @Nullable Network getNetwork() {
return network;
}
/**
* Dequeue the next pending {@link JobWorkItem} from these JobParameters associated with their
* currently running job. Calling this method when there is no more work available and all
* previously dequeued work has been completed will result in the system taking care of
* stopping the job for you --
* you should not call {@link JobService#jobFinished(JobParameters, boolean)} yourself
* (otherwise you risk losing an upcoming JobWorkItem that is being enqueued at the same time).
*
* <p>Once you are done with the {@link JobWorkItem} returned by this method, you must call
* {@link #completeWork(JobWorkItem)} with it to inform the system that you are done
* executing the work. The job will not be finished until all dequeued work has been
* completed. You do not, however, have to complete each returned work item before deqeueing
* the next one -- you can use {@link #dequeueWork()} multiple times before completing
* previous work if you want to process work in parallel, and you can complete the work
* in whatever order you want.</p>
*
* <p>If the job runs to the end of its available time period before all work has been
* completed, it will stop as normal. You should return true from
* {@link JobService#onStopJob(JobParameters)} in order to have the job rescheduled, and by
* doing so any pending as well as remaining uncompleted work will be re-queued
* for the next time the job runs.</p>
*
* <p>This example shows how to construct a JobService that will serially dequeue and
* process work that is available for it:</p>
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/JobWorkService.java
* service}
*
* @return Returns a new {@link JobWorkItem} if there is one pending, otherwise null.
* If null is returned, the system will also stop the job if all work has also been completed.
* (This means that for correct operation, you must always call dequeueWork() after you have
* completed other work, to check either for more work or allow the system to stop the job.)
*/
public @Nullable JobWorkItem dequeueWork() {
try {
return getCallback().dequeueWork(getJobId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Report the completion of executing a {@link JobWorkItem} previously returned by
* {@link #dequeueWork()}. This tells the system you are done with the
* work associated with that item, so it will not be returned again. Note that if this
* is the last work in the queue, completing it here will <em>not</em> finish the overall
* job -- for that to happen, you still need to call {@link #dequeueWork()}
* again.
*
* <p>If you are enqueueing work into a job, you must call this method for each piece
* of work you process. Do <em>not</em> call
* {@link JobService#jobFinished(JobParameters, boolean)}
* or else you can lose work in your queue.</p>
*
* @param work The work you have completed processing, as previously returned by
* {@link #dequeueWork()}
*/
public void completeWork(@NonNull JobWorkItem work) {
try {
if (!getCallback().completeWork(getJobId(), work.getWorkId())) {
throw new IllegalArgumentException("Given work is not active: " + work);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @hide */
@UnsupportedAppUsage
public IJobCallback getCallback() {
return IJobCallback.Stub.asInterface(callback);
}
private JobParameters(Parcel in) {
jobId = in.readInt();
extras = in.readPersistableBundle();
transientExtras = in.readBundle();
if (in.readInt() != 0) {
clipData = ClipData.CREATOR.createFromParcel(in);
clipGrantFlags = in.readInt();
} else {
clipData = null;
clipGrantFlags = 0;
}
callback = in.readStrongBinder();
overrideDeadlineExpired = in.readInt() == 1;
mTriggeredContentUris = in.createTypedArray(Uri.CREATOR);
mTriggeredContentAuthorities = in.createStringArray();
if (in.readInt() != 0) {
network = Network.CREATOR.createFromParcel(in);
} else {
network = null;
}
stopReason = in.readInt();
debugStopReason = in.readString();
}
/** @hide */
public void setStopReason(int reason, String debugStopReason) {
stopReason = reason;
this.debugStopReason = debugStopReason;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(jobId);
dest.writePersistableBundle(extras);
dest.writeBundle(transientExtras);
if (clipData != null) {
dest.writeInt(1);
clipData.writeToParcel(dest, flags);
dest.writeInt(clipGrantFlags);
} else {
dest.writeInt(0);
}
dest.writeStrongBinder(callback);
dest.writeInt(overrideDeadlineExpired ? 1 : 0);
dest.writeTypedArray(mTriggeredContentUris, flags);
dest.writeStringArray(mTriggeredContentAuthorities);
if (network != null) {
dest.writeInt(1);
network.writeToParcel(dest, flags);
} else {
dest.writeInt(0);
}
dest.writeInt(stopReason);
dest.writeString(debugStopReason);
}
public static final @android.annotation.NonNull Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
@Override
public JobParameters createFromParcel(Parcel in) {
return new JobParameters(in);
}
@Override
public JobParameters[] newArray(int size) {
return new JobParameters[size];
}
};
}

View File

@@ -1,191 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.app.job;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.ClipData;
import android.content.Context;
import android.os.Bundle;
import android.os.PersistableBundle;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
* This is an API for scheduling various types of jobs against the framework that will be executed
* in your application's own process.
* <p>
* See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run
* and how to construct them. You will construct these JobInfo objects and pass them to the
* JobScheduler with {@link #schedule(JobInfo)}. When the criteria declared are met, the
* system will execute this job on your application's {@link android.app.job.JobService}.
* You identify the service component that implements the logic for your job when you
* construct the JobInfo using
* {@link android.app.job.JobInfo.Builder#JobInfo.Builder(int,android.content.ComponentName)}.
* </p>
* <p>
* The framework will be intelligent about when it executes jobs, and attempt to batch
* and defer them as much as possible. Typically if you don't specify a deadline on a job, it
* can be run at any moment depending on the current state of the JobScheduler's internal queue.
* <p>
* While a job is running, the system holds a wakelock on behalf of your app. For this reason,
* you do not need to take any action to guarantee that the device stays awake for the
* duration of the job.
* </p>
* <p>You do not
* instantiate this class directly; instead, retrieve it through
* {@link android.content.Context#getSystemService
* Context.getSystemService(Context.JOB_SCHEDULER_SERVICE)}.
*/
@SystemService(Context.JOB_SCHEDULER_SERVICE)
public abstract class JobScheduler {
/** @hide */
@IntDef(prefix = { "RESULT_" }, value = {
RESULT_FAILURE,
RESULT_SUCCESS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Result {}
/**
* Returned from {@link #schedule(JobInfo)} when an invalid parameter was supplied. This can occur
* if the run-time for your job is too short, or perhaps the system can't resolve the
* requisite {@link JobService} in your package.
*/
public static final int RESULT_FAILURE = 0;
/**
* Returned from {@link #schedule(JobInfo)} if this job has been successfully scheduled.
*/
public static final int RESULT_SUCCESS = 1;
/**
* Schedule a job to be executed. Will replace any currently scheduled job with the same
* ID with the new information in the {@link JobInfo}. If a job with the given ID is currently
* running, it will be stopped.
*
* @param job The job you wish scheduled. See
* {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
* you can schedule.
* @return the result of the schedule request.
*/
public abstract @Result int schedule(@NonNull JobInfo job);
/**
* Similar to {@link #schedule}, but allows you to enqueue work for a new <em>or existing</em>
* job. If a job with the same ID is already scheduled, it will be replaced with the
* new {@link JobInfo}, but any previously enqueued work will remain and be dispatched the
* next time it runs. If a job with the same ID is already running, the new work will be
* enqueued for it.
*
* <p>The work you enqueue is later retrieved through
* {@link JobParameters#dequeueWork() JobParameters.dequeueWork}. Be sure to see there
* about how to process work; the act of enqueueing work changes how you should handle the
* overall lifecycle of an executing job.</p>
*
* <p>It is strongly encouraged that you use the same {@link JobInfo} for all work you
* enqueue. This will allow the system to optimally schedule work along with any pending
* and/or currently running work. If the JobInfo changes from the last time the job was
* enqueued, the system will need to update the associated JobInfo, which can cause a disruption
* in execution. In particular, this can result in any currently running job that is processing
* previous work to be stopped and restarted with the new JobInfo.</p>
*
* <p>It is recommended that you avoid using
* {@link JobInfo.Builder#setExtras(PersistableBundle)} or
* {@link JobInfo.Builder#setTransientExtras(Bundle)} with a JobInfo you are using to
* enqueue work. The system will try to compare these extras with the previous JobInfo,
* but there are situations where it may get this wrong and count the JobInfo as changing.
* (That said, you should be relatively safe with a simple set of consistent data in these
* fields.) You should never use {@link JobInfo.Builder#setClipData(ClipData, int)} with
* work you are enqueue, since currently this will always be treated as a different JobInfo,
* even if the ClipData contents are exactly the same.</p>
*
* @param job The job you wish to enqueue work for. See
* {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
* you can schedule.
* @param work New work to enqueue. This will be available later when the job starts running.
* @return the result of the enqueue request.
*/
public abstract @Result int enqueue(@NonNull JobInfo job, @NonNull JobWorkItem work);
/**
*
* @param job The job to be scheduled.
* @param packageName The package on behalf of which the job is to be scheduled. This will be
* used to track battery usage and appIdleState.
* @param userId User on behalf of whom this job is to be scheduled.
* @param tag Debugging tag for dumps associated with this job (instead of the service class)
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public abstract @Result int scheduleAsPackage(@NonNull JobInfo job, @NonNull String packageName,
int userId, String tag);
/**
* Cancel the specified job. If the job is currently executing, it is stopped
* immediately and the return value from its {@link JobService#onStopJob(JobParameters)}
* method is ignored.
*
* @param jobId unique identifier for the job to be canceled, as supplied to
* {@link JobInfo.Builder#JobInfo.Builder(int, android.content.ComponentName)
* JobInfo.Builder(int, android.content.ComponentName)}.
*/
public abstract void cancel(int jobId);
/**
* Cancel <em>all</em> jobs that have been scheduled by the calling application.
*/
public abstract void cancelAll();
/**
* Retrieve all jobs that have been scheduled by the calling application.
*
* @return a list of all of the app's scheduled jobs. This includes jobs that are
* currently started as well as those that are still waiting to run.
*/
public abstract @NonNull List<JobInfo> getAllPendingJobs();
/**
* Look up the description of a scheduled job.
*
* @return The {@link JobInfo} description of the given scheduled job, or {@code null}
* if the supplied job ID does not correspond to any job.
*/
public abstract @Nullable JobInfo getPendingJob(int jobId);
/**
* <b>For internal system callers only!</b>
* Returns a list of all currently-executing jobs.
* @hide
*/
public abstract List<JobInfo> getStartedJobs();
/**
* <b>For internal system callers only!</b>
* Returns a snapshot of the state of all jobs known to the system.
*
* <p class="note">This is a slow operation, so it should be called sparingly.
* @hide
*/
public abstract List<JobSnapshot> getAllJobSnapshots();
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
import android.app.JobSchedulerImpl;
import android.app.SystemServiceRegistry;
import android.content.Context;
import android.os.BatteryStats;
/**
* This class needs to be pre-loaded by zygote. This is where the job scheduler service wrapper
* is registered.
*
* @hide
*/
public class JobSchedulerFrameworkInitializer {
static {
SystemServiceRegistry.registerStaticService(
Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
(b) -> new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)));
BatteryStats.setJobStopReasons(JobParameters.JOB_STOP_REASON_CODES,
JobParameters::getReasonName);
}
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.app.job;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
/**
* <p>Entry point for the callback from the {@link android.app.job.JobScheduler}.</p>
* <p>This is the base class that handles asynchronous requests that were previously scheduled. You
* are responsible for overriding {@link JobService#onStartJob(JobParameters)}, which is where
* you will implement your job logic.</p>
* <p>This service executes each incoming job on a {@link android.os.Handler} running on your
* application's main thread. This means that you <b>must</b> offload your execution logic to
* another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
* in blocking any future callbacks from the JobManager - specifically
* {@link #onStopJob(android.app.job.JobParameters)}, which is meant to inform you that the
* scheduling requirements are no longer being met.</p>
*/
public abstract class JobService extends Service {
private static final String TAG = "JobService";
/**
* Job services must be protected with this permission:
*
* <pre class="prettyprint">
* &#60;service android:name="MyJobService"
* android:permission="android.permission.BIND_JOB_SERVICE" &#62;
* ...
* &#60;/service&#62;
* </pre>
*
* <p>If a job service is declared in the manifest but not protected with this
* permission, that service will be ignored by the system.
*/
public static final String PERMISSION_BIND =
"android.permission.BIND_JOB_SERVICE";
private JobServiceEngine mEngine;
/** @hide */
public final IBinder onBind(Intent intent) {
if (mEngine == null) {
mEngine = new JobServiceEngine(this) {
@Override
public boolean onStartJob(JobParameters params) {
return JobService.this.onStartJob(params);
}
@Override
public boolean onStopJob(JobParameters params) {
return JobService.this.onStopJob(params);
}
};
}
return mEngine.getBinder();
}
/**
* Call this to inform the JobScheduler that the job has finished its work. When the
* system receives this message, it releases the wakelock being held for the job.
* <p>
* You can request that the job be scheduled again by passing {@code true} as
* the <code>wantsReschedule</code> parameter. This will apply back-off policy
* for the job; this policy can be adjusted through the
* {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)} method
* when the job is originally scheduled. The job's initial
* requirements are preserved when jobs are rescheduled, regardless of backed-off
* policy.
* <p class="note">
* A job running while the device is dozing will not be rescheduled with the normal back-off
* policy. Instead, the job will be re-added to the queue and executed again during
* a future idle maintenance window.
* </p>
*
* @param params The parameters identifying this job, as supplied to
* the job in the {@link #onStartJob(JobParameters)} callback.
* @param wantsReschedule {@code true} if this job should be rescheduled according
* to the back-off criteria specified when it was first scheduled; {@code false}
* otherwise.
*/
public final void jobFinished(JobParameters params, boolean wantsReschedule) {
mEngine.jobFinished(params, wantsReschedule);
}
/**
* Called to indicate that the job has begun executing. Override this method with the
* logic for your job. Like all other component lifecycle callbacks, this method executes
* on your application's main thread.
* <p>
* Return {@code true} from this method if your job needs to continue running. If you
* do this, the job remains active until you call
* {@link #jobFinished(JobParameters, boolean)} to tell the system that it has completed
* its work, or until the job's required constraints are no longer satisfied. For
* example, if the job was scheduled using
* {@link JobInfo.Builder#setRequiresCharging(boolean) setRequiresCharging(true)},
* it will be immediately halted by the system if the user unplugs the device from power,
* the job's {@link #onStopJob(JobParameters)} callback will be invoked, and the app
* will be expected to shut down all ongoing work connected with that job.
* <p>
* The system holds a wakelock on behalf of your app as long as your job is executing.
* This wakelock is acquired before this method is invoked, and is not released until either
* you call {@link #jobFinished(JobParameters, boolean)}, or after the system invokes
* {@link #onStopJob(JobParameters)} to notify your job that it is being shut down
* prematurely.
* <p>
* Returning {@code false} from this method means your job is already finished. The
* system's wakelock for the job will be released, and {@link #onStopJob(JobParameters)}
* will not be invoked.
*
* @param params Parameters specifying info about this job, including the optional
* extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle).
* This object serves to identify this specific running job instance when calling
* {@link #jobFinished(JobParameters, boolean)}.
* @return {@code true} if your service will continue running, using a separate thread
* when appropriate. {@code false} means that this job has completed its work.
*/
public abstract boolean onStartJob(JobParameters params);
/**
* This method is called if the system has determined that you must stop execution of your job
* even before you've had a chance to call {@link #jobFinished(JobParameters, boolean)}.
*
* <p>This will happen if the requirements specified at schedule time are no longer met. For
* example you may have requested WiFi with
* {@link android.app.job.JobInfo.Builder#setRequiredNetworkType(int)}, yet while your
* job was executing the user toggled WiFi. Another example is if you had specified
* {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
* idle maintenance window. You are solely responsible for the behavior of your application
* upon receipt of this message; your app will likely start to misbehave if you ignore it.
* <p>
* Once this method returns, the system releases the wakelock that it is holding on
* behalf of the job.</p>
*
* @param params The parameters identifying this job, as supplied to
* the job in the {@link #onStartJob(JobParameters)} callback.
* @return {@code true} to indicate to the JobManager whether you'd like to reschedule
* this job based on the retry criteria provided at job creation-time; or {@code false}
* to end the job entirely. Regardless of the value returned, your job must stop executing.
*/
public abstract boolean onStopJob(JobParameters params);
}

View File

@@ -1,220 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.app.job;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import java.lang.ref.WeakReference;
/**
* Helper for implementing a {@link android.app.Service} that interacts with
* {@link JobScheduler}. This is not intended for use by regular applications, but
* allows frameworks built on top of the platform to create their own
* {@link android.app.Service} that interact with {@link JobScheduler} as well as
* add in additional functionality. If you just want to execute jobs normally, you
* should instead be looking at {@link JobService}.
*/
public abstract class JobServiceEngine {
private static final String TAG = "JobServiceEngine";
/**
* Identifier for a message that will result in a call to
* {@link #onStartJob(android.app.job.JobParameters)}.
*/
private static final int MSG_EXECUTE_JOB = 0;
/**
* Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}.
*/
private static final int MSG_STOP_JOB = 1;
/**
* Message that the client has completed execution of this job.
*/
private static final int MSG_JOB_FINISHED = 2;
private final IJobService mBinder;
/**
* Handler we post jobs to. Responsible for calling into the client logic, and handling the
* callback to the system.
*/
JobHandler mHandler;
static final class JobInterface extends IJobService.Stub {
final WeakReference<JobServiceEngine> mService;
JobInterface(JobServiceEngine service) {
mService = new WeakReference<>(service);
}
@Override
public void startJob(JobParameters jobParams) throws RemoteException {
JobServiceEngine service = mService.get();
if (service != null) {
Message m = Message.obtain(service.mHandler, MSG_EXECUTE_JOB, jobParams);
m.sendToTarget();
}
}
@Override
public void stopJob(JobParameters jobParams) throws RemoteException {
JobServiceEngine service = mService.get();
if (service != null) {
Message m = Message.obtain(service.mHandler, MSG_STOP_JOB, jobParams);
m.sendToTarget();
}
}
}
/**
* Runs on application's main thread - callbacks are meant to offboard work to some other
* (app-specified) mechanism.
* @hide
*/
class JobHandler extends Handler {
JobHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
final JobParameters params = (JobParameters) msg.obj;
switch (msg.what) {
case MSG_EXECUTE_JOB:
try {
boolean workOngoing = JobServiceEngine.this.onStartJob(params);
ackStartMessage(params, workOngoing);
} catch (Exception e) {
Log.e(TAG, "Error while executing job: " + params.getJobId());
throw new RuntimeException(e);
}
break;
case MSG_STOP_JOB:
try {
boolean ret = JobServiceEngine.this.onStopJob(params);
ackStopMessage(params, ret);
} catch (Exception e) {
Log.e(TAG, "Application unable to handle onStopJob.", e);
throw new RuntimeException(e);
}
break;
case MSG_JOB_FINISHED:
final boolean needsReschedule = (msg.arg2 == 1);
IJobCallback callback = params.getCallback();
if (callback != null) {
try {
callback.jobFinished(params.getJobId(), needsReschedule);
} catch (RemoteException e) {
Log.e(TAG, "Error reporting job finish to system: binder has gone" +
"away.");
}
} else {
Log.e(TAG, "finishJob() called for a nonexistent job id.");
}
break;
default:
Log.e(TAG, "Unrecognised message received.");
break;
}
}
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) {
Log.e(TAG, "System unreachable for starting job.");
}
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Attempting to ack a job that has already been processed.");
}
}
}
private void ackStopMessage(JobParameters params, boolean reschedule) {
final IJobCallback callback = params.getCallback();
final int jobId = params.getJobId();
if (callback != null) {
try {
callback.acknowledgeStopMessage(jobId, reschedule);
} catch(RemoteException e) {
Log.e(TAG, "System unreachable for stopping job.");
}
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Attempting to ack a job that has already been processed.");
}
}
}
}
/**
* Create a new engine, ready for use.
*
* @param service The {@link Service} that is creating this engine and in which it will run.
*/
public JobServiceEngine(Service service) {
mBinder = new JobInterface(this);
mHandler = new JobHandler(service.getMainLooper());
}
/**
* Retrieve the engine's IPC interface that should be returned by
* {@link Service#onBind(Intent)}.
*/
public final IBinder getBinder() {
return mBinder.asBinder();
}
/**
* Engine's report that a job has started. See
* {@link JobService#onStartJob(JobParameters) JobService.onStartJob} for more information.
*/
public abstract boolean onStartJob(JobParameters params);
/**
* Engine's report that a job has stopped. See
* {@link JobService#onStopJob(JobParameters) JobService.onStopJob} for more information.
*/
public abstract boolean onStopJob(JobParameters params);
/**
* Call in to engine to report that a job has finished executing. See
* {@link JobService#jobFinished(JobParameters, boolean)} JobService.jobFinished} for more
* information.
*/
public void jobFinished(JobParameters params, boolean needsReschedule) {
if (params == null) {
throw new NullPointerException("params");
}
Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
m.arg2 = needsReschedule ? 1 : 0;
m.sendToTarget();
}
}

View File

@@ -1,19 +0,0 @@
/**
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
parcelable JobSnapshot;

View File

@@ -1,119 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Current-state snapshot of a scheduled job. These snapshots are not used in apps;
* they exist only within the system process across the local call surface where JobStatus
* is not directly accessible at build time.
*
* Constraints that the underlying job does not require are always reported as
* being currently satisfied.
* @hide
*/
public class JobSnapshot implements Parcelable {
private final JobInfo mJob;
private final int mSatisfiedConstraints;
private final boolean mIsRunnable;
public JobSnapshot(JobInfo info, int satisfiedMask, boolean runnable) {
mJob = info;
mSatisfiedConstraints = satisfiedMask;
mIsRunnable = runnable;
}
public JobSnapshot(Parcel in) {
mJob = JobInfo.CREATOR.createFromParcel(in);
mSatisfiedConstraints = in.readInt();
mIsRunnable = in.readBoolean();
}
private boolean satisfied(int flag) {
return (mSatisfiedConstraints & flag) != 0;
}
/**
* Returning JobInfo bound to this snapshot
* @return JobInfo of this snapshot
*/
public JobInfo getJobInfo() {
return mJob;
}
/**
* Is this job actually runnable at this moment?
*/
public boolean isRunnable() {
return mIsRunnable;
}
/**
* @see JobInfo.Builder#setRequiresCharging(boolean)
*/
public boolean isChargingSatisfied() {
return !mJob.isRequireCharging()
|| satisfied(JobInfo.CONSTRAINT_FLAG_CHARGING);
}
/**
* @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
*/
public boolean isBatteryNotLowSatisfied() {
return !mJob.isRequireBatteryNotLow()
|| satisfied(JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW);
}
/**
* @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
*/
public boolean isRequireDeviceIdleSatisfied() {
return !mJob.isRequireDeviceIdle()
|| satisfied(JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE);
}
public boolean isRequireStorageNotLowSatisfied() {
return !mJob.isRequireStorageNotLow()
|| satisfied(JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
mJob.writeToParcel(out, flags);
out.writeInt(mSatisfiedConstraints);
out.writeBoolean(mIsRunnable);
}
public static final @android.annotation.NonNull Creator<JobSnapshot> CREATOR = new Creator<JobSnapshot>() {
@Override
public JobSnapshot createFromParcel(Parcel in) {
return new JobSnapshot(in);
}
@Override
public JobSnapshot[] newArray(int size) {
return new JobSnapshot[size];
}
};
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
/** @hide */
parcelable JobWorkItem;

View File

@@ -1,212 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.job;
import static android.app.job.JobInfo.NETWORK_BYTES_UNKNOWN;
import android.annotation.BytesLong;
import android.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
/**
* A unit of work that can be enqueued for a job using
* {@link JobScheduler#enqueue JobScheduler.enqueue}. See
* {@link JobParameters#dequeueWork() JobParameters.dequeueWork} for more details.
*/
final public class JobWorkItem implements Parcelable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Intent mIntent;
final long mNetworkDownloadBytes;
final long mNetworkUploadBytes;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mDeliveryCount;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mWorkId;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Object mGrants;
/**
* Create a new piece of work, which can be submitted to
* {@link JobScheduler#enqueue JobScheduler.enqueue}.
*
* @param intent The general Intent describing this work.
*/
public JobWorkItem(Intent intent) {
mIntent = intent;
mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
}
/**
* Create a new piece of work, which can be submitted to
* {@link JobScheduler#enqueue JobScheduler.enqueue}.
* <p>
* See {@link JobInfo.Builder#setEstimatedNetworkBytes(long, long)} for
* details about how to estimate network traffic.
*
* @param intent The general Intent describing this work.
* @param downloadBytes The estimated size of network traffic that will be
* downloaded by this job work item, in bytes.
* @param uploadBytes The estimated size of network traffic that will be
* uploaded by this job work item, in bytes.
*/
public JobWorkItem(Intent intent, @BytesLong long downloadBytes, @BytesLong long uploadBytes) {
mIntent = intent;
mNetworkDownloadBytes = downloadBytes;
mNetworkUploadBytes = uploadBytes;
}
/**
* Return the Intent associated with this work.
*/
public Intent getIntent() {
return mIntent;
}
/**
* Return the estimated size of download traffic that will be performed by
* this job, in bytes.
*
* @return Estimated size of download traffic, or
* {@link JobInfo#NETWORK_BYTES_UNKNOWN} when unknown.
*/
public @BytesLong long getEstimatedNetworkDownloadBytes() {
return mNetworkDownloadBytes;
}
/**
* Return the estimated size of upload traffic that will be performed by
* this job work item, in bytes.
*
* @return Estimated size of upload traffic, or
* {@link JobInfo#NETWORK_BYTES_UNKNOWN} when unknown.
*/
public @BytesLong long getEstimatedNetworkUploadBytes() {
return mNetworkUploadBytes;
}
/**
* 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
* job had called {@link JobParameters#completeWork JobParameters.completeWork} for it.
*/
public int getDeliveryCount() {
return mDeliveryCount;
}
/**
* @hide
*/
public void bumpDeliveryCount() {
mDeliveryCount++;
}
/**
* @hide
*/
public void setWorkId(int id) {
mWorkId = id;
}
/**
* @hide
*/
public int getWorkId() {
return mWorkId;
}
/**
* @hide
*/
public void setGrants(Object grants) {
mGrants = grants;
}
/**
* @hide
*/
public Object getGrants() {
return mGrants;
}
public String toString() {
StringBuilder sb = new StringBuilder(64);
sb.append("JobWorkItem{id=");
sb.append(mWorkId);
sb.append(" intent=");
sb.append(mIntent);
if (mNetworkDownloadBytes != NETWORK_BYTES_UNKNOWN) {
sb.append(" downloadBytes=");
sb.append(mNetworkDownloadBytes);
}
if (mNetworkUploadBytes != NETWORK_BYTES_UNKNOWN) {
sb.append(" uploadBytes=");
sb.append(mNetworkUploadBytes);
}
if (mDeliveryCount != 0) {
sb.append(" dcount=");
sb.append(mDeliveryCount);
}
sb.append("}");
return sb.toString();
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
if (mIntent != null) {
out.writeInt(1);
mIntent.writeToParcel(out, 0);
} else {
out.writeInt(0);
}
out.writeLong(mNetworkDownloadBytes);
out.writeLong(mNetworkUploadBytes);
out.writeInt(mDeliveryCount);
out.writeInt(mWorkId);
}
public static final @android.annotation.NonNull Parcelable.Creator<JobWorkItem> CREATOR
= new Parcelable.Creator<JobWorkItem>() {
public JobWorkItem createFromParcel(Parcel in) {
return new JobWorkItem(in);
}
public JobWorkItem[] newArray(int size) {
return new JobWorkItem[size];
}
};
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
JobWorkItem(Parcel in) {
if (in.readInt() != 0) {
mIntent = Intent.CREATOR.createFromParcel(in);
} else {
mIntent = null;
}
mNetworkDownloadBytes = in.readLong();
mNetworkUploadBytes = in.readLong();
mDeliveryCount = in.readInt();
mWorkId = in.readInt();
}
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.job;
import android.app.job.JobInfo;
import android.util.proto.ProtoOutputStream;
import java.util.List;
/**
* JobScheduler local system service interface.
* {@hide} Only for use within the system server.
*/
public interface JobSchedulerInternal {
/**
* Returns a list of pending jobs scheduled by the system service.
*/
List<JobInfo> getSystemScheduledPendingJobs();
/**
* Cancel the jobs for a given uid (e.g. when app data is cleared)
*/
void cancelJobsForUid(int uid, String reason);
/**
* These are for activity manager to communicate to use what is currently performing backups.
*/
void addBackingUpUid(int uid);
void removeBackingUpUid(int uid);
void clearAllBackingUpUids();
/**
* The user has started interacting with the app. Take any appropriate action.
*/
void reportAppUsage(String packageName, int userId);
/**
* Report a snapshot of sync-related jobs back to the sync manager
*/
JobStorePersistStats getPersistStats();
/**
* Stats about the first load after boot and the most recent save.
*/
public class JobStorePersistStats {
public int countAllJobsLoaded = -1;
public int countSystemServerJobsLoaded = -1;
public int countSystemSyncManagerJobsLoaded = -1;
public int countAllJobsSaved = -1;
public int countSystemServerJobsSaved = -1;
public int countSystemSyncManagerJobsSaved = -1;
public JobStorePersistStats() {
}
public JobStorePersistStats(JobStorePersistStats source) {
countAllJobsLoaded = source.countAllJobsLoaded;
countSystemServerJobsLoaded = source.countSystemServerJobsLoaded;
countSystemSyncManagerJobsLoaded = source.countSystemSyncManagerJobsLoaded;
countAllJobsSaved = source.countAllJobsSaved;
countSystemServerJobsSaved = source.countSystemServerJobsSaved;
countSystemSyncManagerJobsSaved = source.countSystemSyncManagerJobsSaved;
}
@Override
public String toString() {
return "FirstLoad: "
+ countAllJobsLoaded + "/"
+ countSystemServerJobsLoaded + "/"
+ countSystemSyncManagerJobsLoaded
+ " LastSave: "
+ countAllJobsSaved + "/"
+ countSystemServerJobsSaved + "/"
+ countSystemSyncManagerJobsSaved;
}
/**
* Write the persist stats to the specified field.
*/
public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
final long flToken = proto.start(JobStorePersistStatsProto.FIRST_LOAD);
proto.write(JobStorePersistStatsProto.Stats.NUM_TOTAL_JOBS, countAllJobsLoaded);
proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SERVER_JOBS,
countSystemServerJobsLoaded);
proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SYNC_MANAGER_JOBS,
countSystemSyncManagerJobsLoaded);
proto.end(flToken);
final long lsToken = proto.start(JobStorePersistStatsProto.LAST_SAVE);
proto.write(JobStorePersistStatsProto.Stats.NUM_TOTAL_JOBS, countAllJobsSaved);
proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SERVER_JOBS,
countSystemServerJobsSaved);
proto.write(JobStorePersistStatsProto.Stats.NUM_SYSTEM_SYNC_MANAGER_JOBS,
countSystemSyncManagerJobsSaved);
proto.end(lsToken);
proto.end(token);
}
}
}